feat: Working initial nodes

Receive, Collection, URL parsing for models, root object unpacking
This commit is contained in:
Alan Rynne
2024-12-05 11:00:37 +01:00
parent 1ff861f9db
commit 7ec01ed39f
24 changed files with 1391 additions and 45 deletions
@@ -0,0 +1,24 @@
using Microsoft.Extensions.DependencyInjection;
namespace Speckle.Connectors.Grasshopper8.Components.BaseComponents;
public abstract class SpeckleScopedTaskCapableComponent<TInput, TOutput>(
string name,
string nickname,
string description,
string category,
string subCategory
) : SpeckleTaskCapableComponent<TInput, TOutput>(name, nickname, description, category, subCategory)
{
protected override Task<TOutput> PerformTask(TInput input, CancellationToken cancellationToken = default)
{
using var scope = PriorityLoader.Container.CreateScope();
return PerformScopedTask(input, scope, cancellationToken);
}
protected abstract Task<TOutput> PerformScopedTask(
TInput input,
IServiceScope scope,
CancellationToken cancellationToken = default
);
}
@@ -0,0 +1,60 @@
using Grasshopper.Kernel;
using Speckle.Sdk;
namespace Speckle.Connectors.Grasshopper8.Components.BaseComponents;
public abstract class SpeckleTaskCapableComponent<TInput, TOutput>(
string name,
string nickname,
string description,
string category,
string subCategory
) : GH_TaskCapableComponent<TOutput>(name, nickname, description, category, subCategory)
{
protected override void SolveInstance(IGH_DataAccess da)
{
//TODO: We're missing activity and logging here. Will enable it for all inherited classes.
if (InPreSolve)
{
// Collect the data and create the task
try
{
var input = GetInput(da);
TaskList.Add(PerformTask(input, CancelToken));
}
catch (SpeckleException e)
{
Console.WriteLine(e);
}
return;
}
if (!GetSolveResults(da, out TOutput result))
{
// INFO: This will run synchronously. Useful for Rhino.Compute runs, but can also be enabled by user.
try
{
TInput input = GetInput(da);
var syncResult = PerformTask(input).Result;
result = syncResult;
}
catch (SpeckleException e)
{
Console.WriteLine(e);
return;
}
}
if (result is not null)
{
SetOutput(da, result);
}
}
protected abstract TInput GetInput(IGH_DataAccess da);
protected abstract void SetOutput(IGH_DataAccess da, TOutput result);
protected abstract Task<TOutput> PerformTask(TInput input, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,165 @@
using Grasshopper.Kernel;
using Speckle.Connectors.Grasshopper8.Components.BaseComponents;
using Speckle.Connectors.Grasshopper8.Parameters;
using Speckle.Sdk;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
namespace Speckle.Connectors.Grasshopper8.Components.Collections;
public record CreateCollectionComponentInput(
Collection? Collection,
string? Name,
List<Base>? Elements,
List<Collection>? Collections
);
public record CreateCollectionComponentOutput(Collection Collection);
public class CreateCollectionComponent
: SpeckleTaskCapableComponent<CreateCollectionComponentInput, CreateCollectionComponentOutput>
{
public CreateCollectionComponent()
: base("Create Collection", "CrCol", "Creates a new collection", "Speckle", "Collections") { }
public override Guid ComponentGuid => new("6A9EDFDE-8AC4-4E28-B455-45DF42E2172B");
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
var colIndex = pManager.AddParameter(
new SpeckleCollectionParam(GH_ParamAccess.item),
"collection",
"Collection",
"Collection",
GH_ParamAccess.item
);
var nameIndex = pManager.AddTextParameter("Name", "Name", "Name of the collection", GH_ParamAccess.item);
var elementsIndex = pManager.AddParameter(
new SpeckleObjectParam(GH_ParamAccess.list),
"elements",
"Elements",
"Elements of the collection",
GH_ParamAccess.list
);
var collectionsIndex = pManager.AddParameter(
new SpeckleCollectionParam(GH_ParamAccess.list),
"collections",
"Collections",
"Sub-collections of the collection",
GH_ParamAccess.list
);
pManager[colIndex].Optional = true;
pManager[nameIndex].Optional = true;
pManager[elementsIndex].Optional = true;
pManager[collectionsIndex].Optional = true;
}
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
var colIndex = pManager.AddParameter(
new SpeckleCollectionParam(GH_ParamAccess.item),
"collection",
"Collection",
"Collection",
GH_ParamAccess.item
);
var nameIndex = pManager.AddTextParameter("Name", "Name", "Name of the collection", GH_ParamAccess.item);
var elementsIndex = pManager.AddParameter(
new SpeckleObjectParam(GH_ParamAccess.list),
"elements",
"Elements",
"Elements of the collection",
GH_ParamAccess.list
);
var collectionsIndex = pManager.AddParameter(
new SpeckleCollectionParam(GH_ParamAccess.list),
"collections",
"Collections",
"Sub-collections of the collection",
GH_ParamAccess.list
);
pManager[colIndex].Optional = true;
pManager[nameIndex].Optional = true;
pManager[elementsIndex].Optional = true;
pManager[collectionsIndex].Optional = true;
}
protected override CreateCollectionComponentInput GetInput(IGH_DataAccess da)
{
Collection? collection = null;
string? name = "";
List<Base>? elements = new List<Base>();
List<Collection>? collections = new List<Collection>();
da.GetData(0, ref collection);
da.GetData(1, ref name);
da.GetDataList(2, elements);
da.GetDataList(3, collections);
return new CreateCollectionComponentInput(collection, name, elements, collections);
}
protected override void SetOutput(IGH_DataAccess da, CreateCollectionComponentOutput result)
{
da.SetData(0, result.Collection);
da.SetData(1, result.Collection.name);
da.SetDataList(2, result.Collection.elements.Where(e => e is not Collection));
da.SetDataList(3, result.Collection.elements.Where(e => e is Collection));
}
protected override Task<CreateCollectionComponentOutput> PerformTask(
CreateCollectionComponentInput input,
CancellationToken cancellationToken = default
)
{
if (input.Collection is null)
{
// Create new collection
if (input.Name is null)
{
throw new SpeckleException("New collections must have a name");
}
var collection = new Collection(input.Name) { elements = input.Elements ?? new List<Base>() };
var result = new CreateCollectionComponentOutput(collection);
return Task.FromResult(result);
}
else
{
var collection = new Collection(input.Collection.name) { elements = input.Collection.elements };
// Create new collection
if (input.Name is not null && input.Name.Length != 0)
{
collection.name = input.Name;
}
var elements = new List<Base>();
if (input.Elements is not null && input.Elements.Count != 0)
{
elements.AddRange(input.Elements);
}
else
{
elements.AddRange(collection.elements.Where(e => e is not Collection));
}
if (input.Collections is not null && input.Collections.Count != 0)
{
elements.AddRange(input.Collections);
}
else
{
elements.AddRange(collection.elements.Where(e => e is Collection));
}
var result = new CreateCollectionComponentOutput(collection);
return Task.FromResult(result);
}
}
}
@@ -0,0 +1,195 @@
using Grasshopper.Kernel;
using Microsoft.Extensions.DependencyInjection;
using Speckle.Connectors.Common.Conversion;
using Speckle.Connectors.Common.Instances;
using Speckle.Connectors.Common.Operations.Receive;
using Speckle.Connectors.Grasshopper8.Components.BaseComponents;
using Speckle.Connectors.Grasshopper8.Parameters;
using Speckle.Sdk;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
using Speckle.Sdk.Models.Instances;
namespace Speckle.Connectors.Grasshopper8.Components.Collections;
public record UnpackRootObjectComponentInput(Base RootObject) { }
public record UnpackRootObjectComponentOutput(
List<Base> Elements,
List<string> ElementPaths,
List<IInstanceComponent> Instances,
List<string> InstancePaths
) { }
public class UnpackRootObjectComponent
: SpeckleScopedTaskCapableComponent<UnpackRootObjectComponentInput, UnpackRootObjectComponentOutput>
{
public UnpackRootObjectComponent()
: base("Unpack Root Object", "SURO", "Unpacks the root object from a receive operation", "Speckle", "Collections")
{ }
public override Guid ComponentGuid => new Guid("3C770686-20D5-434C-99E3-BDE735E8267F");
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
pManager.AddParameter(new SpeckleObjectParam(GH_ParamAccess.item));
}
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
pManager.AddTextParameter("Element Paths", "EP", "Path to the element in the collection tree", GH_ParamAccess.list);
pManager.AddParameter(new SpeckleObjectParam(), "Elements", "E", "Elements", GH_ParamAccess.list);
pManager.AddTextParameter(
"Instance Paths",
"IP",
"Path to the instance in the collection tree",
GH_ParamAccess.list
);
pManager.AddParameter(new SpeckleObjectParam(), "Instances", "I", "Instances", GH_ParamAccess.list);
}
protected override UnpackRootObjectComponentInput GetInput(IGH_DataAccess da)
{
Base? baseObject = null;
da.GetData(0, ref baseObject);
if (baseObject == null)
{
throw new SpeckleException("No base object provided");
}
return new UnpackRootObjectComponentInput(baseObject);
}
protected override void SetOutput(IGH_DataAccess da, UnpackRootObjectComponentOutput result)
{
da.SetDataList(0, result.ElementPaths);
da.SetDataList(1, result.Elements);
da.SetDataList(2, result.InstancePaths);
da.SetDataList(3, result.Instances);
}
protected override async Task<UnpackRootObjectComponentOutput> PerformScopedTask(
UnpackRootObjectComponentInput input,
IServiceScope scope,
CancellationToken cancellationToken = default
)
{
var rootObjectUnpacker = scope.ServiceProvider.GetRequiredService<RootObjectUnpacker>();
var contextUnpacker = scope.ServiceProvider.GetRequiredService<TraversalContextUnpacker>();
var unpackedRoot = rootObjectUnpacker.Unpack(input.RootObject);
// 2 - Split atomic objects and instance components with their path
var (atomicObjects, instanceComponents) = rootObjectUnpacker.SplitAtomicObjectsAndInstances(
unpackedRoot.ObjectsToConvert
);
var atomicObjectsWithPath = contextUnpacker.GetAtomicObjectsWithPath(atomicObjects);
var instanceComponentsWithPath = contextUnpacker.GetInstanceComponentsWithPath(instanceComponents);
// 2.1 - these are not captured by traversal, so we need to re-add them here
if (unpackedRoot.DefinitionProxies != null && unpackedRoot.DefinitionProxies.Count > 0)
{
var transformed = unpackedRoot.DefinitionProxies.Select(proxy =>
(Array.Empty<Collection>(), proxy as IInstanceComponent)
);
instanceComponentsWithPath.AddRange(transformed);
}
var applicationIdMap = new Dictionary<string, Base>();
atomicObjectsWithPath.ForEach(a => applicationIdMap.Add(a.current.applicationId ?? a.current.id, a.current));
var instanceResult = await ProcessInstances(instanceComponentsWithPath, applicationIdMap).ConfigureAwait(false);
foreach (string objId in instanceResult.ConsumedObjectIds)
{
var indexAtomic = atomicObjectsWithPath.FindIndex(o => o.current.id == objId);
if (indexAtomic != -1)
{
atomicObjectsWithPath.RemoveAt(indexAtomic);
}
// HACK: Why is instancecomponent not ISpeckleObject?
var indexInstance = instanceComponentsWithPath.FindIndex(o => ((Base)o.instance).id == objId);
if (indexInstance != -1)
{
instanceComponentsWithPath.RemoveAt(indexInstance);
}
}
var elements = new List<Base>();
var instances = new List<IInstanceComponent>();
var elementPaths = new List<string>();
var instancePaths = new List<string>();
atomicObjectsWithPath.ForEach(atomicObj =>
{
var names = atomicObj.path.Select(p => p.name);
elements.Add(atomicObj.current);
elementPaths.Add(string.Join("::", names));
});
instanceComponentsWithPath.ForEach(instanceObj =>
{
var names = instanceObj.path.Select(p => p.name);
instances.Add(instanceObj.instance);
instancePaths.Add(string.Join("::", names));
});
var output = new UnpackRootObjectComponentOutput(elements, elementPaths, instances, instancePaths);
return output;
}
public Task<BakeResult> ProcessInstances(
IReadOnlyCollection<(Collection[] collectionPath, IInstanceComponent obj)> instanceComponents,
Dictionary<string, Base> applicationIdMap
)
{
var sortedInstanceComponents = instanceComponents
.OrderByDescending(x => x.obj.maxDepth) // Sort by max depth, so we start baking from the deepest element first
.ThenBy(x => x.obj is InstanceDefinitionProxy ? 0 : 1) // Ensure we bake the deepest definition first, then any instances that depend on it
.ToList();
var definitionObjectsMap = new Dictionary<string, (InstanceDefinitionProxy, List<Base>)>();
var consumedObjectIds = new List<string>();
foreach (var (layerCollection, instanceOrDefinition) in sortedInstanceComponents)
{
try
{
if (instanceOrDefinition is InstanceDefinitionProxy definitionProxy)
{
var currentSpeckleObjects = definitionProxy
.objects.Where(applicationIdMap.ContainsKey)
.Select(x => applicationIdMap[x])
.ToList();
definitionObjectsMap.Add(
definitionProxy.applicationId ?? definitionProxy.id,
(definitionProxy, currentSpeckleObjects)
);
consumedObjectIds.AddRange(currentSpeckleObjects.Select(o => o.id));
consumedObjectIds.Add(definitionProxy.id);
}
if (
instanceOrDefinition is InstanceProxy instanceProxy
&& definitionObjectsMap.TryGetValue(instanceProxy.definitionId, out var definition)
)
{
instanceProxy["__geometry"] = definition.Item2;
instanceProxy["__definition"] = definition.Item1;
applicationIdMap[instanceProxy.applicationId ?? instanceProxy.id] = instanceProxy;
}
}
catch (Exception ex) when (!ex.IsFatal())
{
//_logger.LogError(ex, "Failed to create an instance from proxy");
}
}
//await Task.Yield();
BakeResult processInstances = new(new List<string>(), consumedObjectIds, new List<ReceiveConversionResult>());
return Task.FromResult(processInstances);
}
}
@@ -0,0 +1,156 @@
using Grasshopper.Kernel;
using Microsoft.Extensions.DependencyInjection;
using Rhino;
using Rhino.Geometry;
using Speckle.Connectors.Grasshopper8.Components.BaseComponents;
using Speckle.Connectors.Grasshopper8.Parameters;
using Speckle.Converters.Common;
using Speckle.Converters.Rhino;
using Speckle.DoubleNumerics;
using Speckle.Sdk;
using Speckle.Sdk.Common;
using Speckle.Sdk.Common.Exceptions;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Instances;
namespace Speckle.Connectors.Grasshopper8.Components.Operations.Conversion;
public static class RhinoUnitsExtension
{
public static string ToSpeckleString(this UnitSystem unitSystem)
{
switch (unitSystem)
{
case UnitSystem.None:
return Units.Meters;
case UnitSystem.Millimeters:
return Units.Millimeters;
case UnitSystem.Centimeters:
return Units.Centimeters;
case UnitSystem.Meters:
return Units.Meters;
case UnitSystem.Kilometers:
return Units.Kilometers;
case UnitSystem.Inches:
return Units.Inches;
case UnitSystem.Feet:
return Units.Feet;
case UnitSystem.Yards:
return Units.Yards;
case UnitSystem.Miles:
return Units.Miles;
case UnitSystem.Unset:
return Units.Meters;
default:
throw new UnitNotSupportedException($"The Unit System \"{unitSystem}\" is unsupported.");
}
}
}
public class ToNativeConversion()
: SpeckleScopedTaskCapableComponent<Base, List<GeometryBase>>(
"ToNativeConversion",
"STN",
"Converts a speckle object to rhino",
"Speckle",
"Conversion"
)
{
public override Guid ComponentGuid => new Guid("38BAB10C-4D80-4E0C-8235-A87C3E66F55F");
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
pManager.AddParameter(new SpeckleObjectParam(GH_ParamAccess.item));
}
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
pManager.AddGeometryParameter("Geometry", "Geometry", "Geometry", GH_ParamAccess.list);
}
protected override Base GetInput(IGH_DataAccess da)
{
Base? input = null;
if (!da.GetData(0, ref input) || input is null)
{
throw new SpeckleException("Input is not valid");
}
return input;
}
protected override void SetOutput(IGH_DataAccess da, List<GeometryBase> result)
{
da.SetDataList(0, result);
}
protected override Task<List<GeometryBase>> PerformScopedTask(
Base input,
IServiceScope scope,
CancellationToken cancellationToken = default
)
{
var rhinoConversionSettingsFactory = scope.ServiceProvider.GetRequiredService<IRhinoConversionSettingsFactory>();
scope
.ServiceProvider.GetRequiredService<IConverterSettingsStore<RhinoConversionSettings>>()
.Initialize(rhinoConversionSettingsFactory.Create(RhinoDoc.ActiveDoc));
var rootConverter = scope.ServiceProvider.GetRequiredService<IRootToHostConverter>();
if (input is InstanceProxy proxy)
{
var geometries = proxy["__geometry"] as List<Base>;
var converted = geometries.SelectMany(g => Convert(g, rootConverter)).ToList();
var transform = MatrixToTransform(proxy.transform, proxy.units);
converted.ForEach(c => c.Transform(transform));
return Task.FromResult(converted);
}
return Task.FromResult(Convert(input, rootConverter));
}
private List<GeometryBase> Convert(Base input, IRootToHostConverter rootConverter)
{
var result = rootConverter.Convert(input);
if (result is GeometryBase geometry)
{
return new List<GeometryBase> { geometry };
}
else if (result is List<GeometryBase> geometryList)
{
return geometryList;
}
throw new SpeckleException("Failed to convert input to rhino");
}
private Transform MatrixToTransform(Matrix4x4 matrix, string units)
{
var currentDoc = RhinoDoc.ActiveDoc; // POC: too much right now to interface around
var conversionFactor = Units.GetConversionFactor(units, currentDoc.ModelUnitSystem.ToSpeckleString());
var t = Transform.Identity;
t.M00 = matrix.M11;
t.M01 = matrix.M12;
t.M02 = matrix.M13;
t.M03 = matrix.M14 * conversionFactor;
t.M10 = matrix.M21;
t.M11 = matrix.M22;
t.M12 = matrix.M23;
t.M13 = matrix.M24 * conversionFactor;
t.M20 = matrix.M31;
t.M21 = matrix.M32;
t.M22 = matrix.M33;
t.M23 = matrix.M34 * conversionFactor;
t.M30 = matrix.M41;
t.M31 = matrix.M42;
t.M32 = matrix.M43;
t.M33 = matrix.M44;
return t;
}
}
@@ -0,0 +1,97 @@
using Grasshopper.Kernel;
using Microsoft.Extensions.DependencyInjection;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.Grasshopper8.Components.BaseComponents;
using Speckle.Connectors.Grasshopper8.HostApp;
using Speckle.Connectors.Grasshopper8.Parameters;
using Speckle.Sdk;
using Speckle.Sdk.Api;
using Speckle.Sdk.Credentials;
using Speckle.Sdk.Models;
namespace Speckle.Connectors.Grasshopper8.Components.Operations.Receive;
public class ReceiveComponentOutput
{
public Base RootObject { get; set; }
}
public class ReceiveComponent : SpeckleScopedTaskCapableComponent<SpeckleUrlModelResource, ReceiveComponentOutput>
{
public ReceiveComponent()
: base("Receive from Speckle", "RFS", "Receive objects from speckle", "Speckle", "Operations") { }
public override Guid ComponentGuid => new("74954F59-B1B7-41FD-97DE-4C6B005F2801");
protected override Bitmap Icon => BitmapBuilder.CreateSquareIconBitmap("R");
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
pManager.AddParameter(new SpeckleUrlModelResourceParam(GH_ParamAccess.item));
}
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
pManager.AddParameter(
new SpeckleObjectParam(GH_ParamAccess.item),
"Model",
"model",
"The model object for the received version",
GH_ParamAccess.item
);
}
protected override SpeckleUrlModelResource GetInput(IGH_DataAccess da)
{
SpeckleUrlModelResource? url = null;
da.GetData(0, ref url);
if (url is null)
{
throw new SpeckleException("Speckle url is null");
}
return url;
}
protected override void SetOutput(IGH_DataAccess da, ReceiveComponentOutput result)
{
da.SetData(0, result.RootObject);
Message = "Done";
}
protected override async Task<ReceiveComponentOutput> PerformScopedTask(
SpeckleUrlModelResource input,
IServiceScope scope,
CancellationToken cancellationToken = default
)
{
// TODO: Resolving dependencies here may be overkill in most cases. Must re-evaluate.
var accountManager = scope.ServiceProvider.GetRequiredService<AccountService>();
var clientFactory = scope.ServiceProvider.GetRequiredService<IClientFactory>();
var receiveOperation = scope.ServiceProvider.GetRequiredService<GrasshopperReceiveOperation>();
// Do the thing 👇🏼
// TODO: Get any account for this server, as we don't have a mechanism yet to pass accountIds through
var account = accountManager.GetAccountWithServerUrlFallback("", new Uri(input.Server));
if (account is null)
{
throw new SpeckleAccountManagerException($"No default account was found");
}
using var client = clientFactory.Create(account);
var receiveInfo = await input.GetReceiveInfo(client, cancellationToken).ConfigureAwait(false);
var progress = new Progress<CardProgress>(_ =>
{
// TODO: Progress only makes sense in non-blocking async receive, which is not supported yet.
// Message = $"{progress.Status}: {progress.Progress}";
});
var root = await receiveOperation
.ReceiveCommitObject(receiveInfo, progress, cancellationToken)
.ConfigureAwait(false);
return new ReceiveComponentOutput { RootObject = root };
}
}
@@ -3,14 +3,14 @@ using Microsoft.Extensions.DependencyInjection;
using Rhino;
using Rhino.Geometry;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.Grasshopper8.Operations.Receive;
using Speckle.Connectors.Grasshopper8.HostApp;
using Speckle.Converters.Common;
using Speckle.Converters.Rhino;
using Speckle.Sdk.Common;
using Speckle.Sdk.Credentials;
using Speckle.Sdk.Models;
namespace Speckle.Connectors.Grasshopper8;
namespace Speckle.Connectors.Grasshopper8.Components;
public class SpeckleFirstComponent : GH_TaskCapableComponent<List<object?>>
{
@@ -24,7 +24,7 @@ public class SpeckleFirstComponent : GH_TaskCapableComponent<List<object?>>
/// new tabs/panels will automatically be created.
/// </summary>
public SpeckleFirstComponent()
: base("Send to Speckle", "STP", "Sends objects to speckle", "Speckle", "Operations")
: base("First Speckle Component", "STP", "Sends objects to speckle", "Speckle", "Other")
{
_accountManager = PriorityLoader.Container.NotNull().GetRequiredService<AccountManager>();
}
@@ -45,8 +45,8 @@ public class SpeckleFirstComponent : GH_TaskCapableComponent<List<object?>>
{
// Collect the data and create the task
string url = GetInput(da);
TaskList.Add(PerformReceiveOperation(url, CancelToken));
Message = "Receiving...";
TaskList.Add(PerformReceiveOperation(url, CancelToken));
return;
}
@@ -125,9 +125,10 @@ public class SpeckleFirstComponent : GH_TaskCapableComponent<List<object?>>
throw new NotSupportedException($"Unsupported conversion result type: {conversionResult}");
}
//results.Add(ghConversionResult.Source);
if (ghConversionResult.Result is GeometryBase geometryBase)
{
//var guid = BakeObject(geometryBase, obj, atts);
results.Add(geometryBase);
}
else if (ghConversionResult.Result is List<GeometryBase> geometryBases) // one to many raw encoding case
{
@@ -137,7 +138,6 @@ public class SpeckleFirstComponent : GH_TaskCapableComponent<List<object?>>
{
results.AddRange(fallbackConversionResult.Select(o => o.Item1));
}
results.Add(ghConversionResult.Result);
}
return results;
@@ -0,0 +1,48 @@
using Grasshopper.Kernel;
using Speckle.Connectors.Grasshopper8.Components.BaseComponents;
using Speckle.Connectors.Grasshopper8.HostApp;
using Speckle.Connectors.Grasshopper8.Parameters;
namespace Speckle.Connectors.Grasshopper8.Components;
public class SpeckleResourceFromUrlComponent : SpeckleTaskCapableComponent<string, SpeckleUrlModelResource[]>
{
public SpeckleResourceFromUrlComponent()
: base("Speckle Resource From Url", "spcklUrl", "Speckle resource from url", "Speckle", "Resources") { }
public override Guid ComponentGuid => new("A55C74C6-D955-4822-84BB-2266A2B965EE");
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
pManager.AddTextParameter("URL", "URL", "URL to send to resource", GH_ParamAccess.item);
}
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
pManager.AddParameter(new SpeckleUrlModelResourceParam(GH_ParamAccess.list));
}
protected override string GetInput(IGH_DataAccess da)
{
string url = string.Empty;
da.GetData(0, ref url);
return url;
}
protected override void SetOutput(IGH_DataAccess da, SpeckleUrlModelResource[] result)
{
da.SetDataList(0, result);
}
protected override Task<SpeckleUrlModelResource[]> PerformTask(
string input,
CancellationToken cancellationToken = default
)
{
var resources = SpeckleResourceBuilder.FromUrlString(input);
// TODO: Here's where we can validate the resources and throw or not?
return Task.FromResult(resources);
}
}
@@ -0,0 +1,81 @@
using System.Drawing.Drawing2D;
namespace Speckle.Connectors.Grasshopper8.HostApp;
public static class BitmapBuilder
{
public static Bitmap CreateSquareIconBitmap(string text, int width = 24, int height = 24)
{
Bitmap bitmap = new(width, height);
using Graphics graphics = Graphics.FromImage(bitmap);
// Enable high-quality rendering
graphics.SmoothingMode = SmoothingMode.AntiAlias;
// Set background to transparent
graphics.Clear(Color.Transparent);
// Rectangle with a 1px offset
Rectangle squareRect = new(1, 1, width - 2, height - 2);
using (Brush blueBrush = new SolidBrush(Color.Blue))
{
graphics.FillRectangle(blueBrush, squareRect);
}
// Draw white letters in the center
using (Font font = new("Arial", 8, FontStyle.Bold, GraphicsUnit.Pixel))
using (Brush whiteBrush = new SolidBrush(Color.White))
{
StringFormat format = new() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
graphics.DrawString(text, font, whiteBrush, new RectangleF(1, 1, width - 2, height - 2), format);
}
return bitmap;
}
public static Bitmap CreateHexagonalBitmap(string text, int width = 24, int height = 24)
{
Bitmap bitmap = new(width, height);
using Graphics graphics = Graphics.FromImage(bitmap);
// Enable high-quality rendering
graphics.SmoothingMode = SmoothingMode.AntiAlias;
// Set background to transparent
graphics.Clear(Color.Transparent);
// Calculate hexagon points centered within the bitmap
float side = (width - 2) / 2.236f; // 2.236f approximates 4 / √3 for regular hex dimensions
float h = side * (float)Math.Sqrt(3) / 2;
float centerX = width / 2f;
float centerY = height / 2f;
Point[] hexagonPoints =
[
new((int)(centerX - side / 2), (int)(centerY - h)),
new((int)(centerX + side / 2), (int)(centerY - h)),
new((int)(centerX + side), (int)centerY),
new((int)(centerX + side / 2), (int)(centerY + h)),
new((int)(centerX - side / 2), (int)(centerY + h)),
new((int)(centerX - side), (int)centerY)
];
using (Brush blueBrush = new SolidBrush(Color.Blue))
{
graphics.FillPolygon(blueBrush, hexagonPoints);
}
// Draw white letters in the center
using Font font = new("Monospace", 10, FontStyle.Bold, GraphicsUnit.Pixel);
using Brush whiteBrush = new SolidBrush(Color.White);
StringFormat format = new() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
graphics.DrawString(text, font, whiteBrush, new RectangleF(0, 1, width, height), format);
return bitmap;
}
}
@@ -11,11 +11,12 @@ using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
using Speckle.Sdk.Models.Instances;
namespace Speckle.Connectors.Grasshopper8.Operations.Receive;
namespace Speckle.Connectors.Grasshopper8.HostApp;
public sealed class GrasshopperReceiveConversionResult : ReceiveConversionResult
{
public object? Result { get; set; }
public Base Source { get; set; }
public GrasshopperReceiveConversionResult(
Status status,
@@ -28,6 +29,7 @@ public sealed class GrasshopperReceiveConversionResult : ReceiveConversionResult
: base(status, source, resultId, resultType, exception)
{
Result = result;
Source = source;
}
}
@@ -146,6 +148,8 @@ public class GrasshopperHostObjectBuilder : IHostObjectBuilder
conversionResults.Add(
new GrasshopperReceiveConversionResult(Status.SUCCESS, obj, result, null, result.GetType().ToString())
);
// applicationIdMap[obj.applicationId ?? obj.id] = conversionIds;
convertActivity?.SetStatus(SdkActivityStatusCode.Ok);
}
catch (Exception ex) when (!ex.IsFatal())
@@ -0,0 +1,100 @@
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.Logging;
using Speckle.Sdk.Api;
using Speckle.Sdk.Credentials;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models;
using Speckle.Sdk.Transports;
namespace Speckle.Connectors.Grasshopper8.HostApp;
public class GrasshopperReceiveOperation
{
private readonly AccountService _accountService;
private readonly IServerTransportFactory _serverTransportFactory;
private readonly IProgressDisplayManager _progressDisplayManager;
private readonly ISdkActivityFactory _activityFactory;
private readonly IOperations _operations;
private readonly IClientFactory _clientFactory;
public GrasshopperReceiveOperation(
AccountService accountService,
IServerTransportFactory serverTransportFactory,
IProgressDisplayManager progressDisplayManager,
ISdkActivityFactory activityFactory,
IOperations operations,
IClientFactory clientFactory
)
{
_accountService = accountService;
_serverTransportFactory = serverTransportFactory;
_progressDisplayManager = progressDisplayManager;
_activityFactory = activityFactory;
_operations = operations;
_clientFactory = clientFactory;
}
public async Task<Base> ReceiveCommitObject(
ReceiveInfo receiveInfo,
IProgress<CardProgress> onOperationProgressed,
CancellationToken cancellationToken
)
{
using var execute = _activityFactory.Start("Receive Operation");
execute?.SetTag("receiveInfo", receiveInfo);
// 2 - Check account exist
Account account = _accountService.GetAccountWithServerUrlFallback(receiveInfo.AccountId, receiveInfo.ServerUrl);
using Client apiClient = _clientFactory.Create(account);
using var userScope = ActivityScope.SetTag(Consts.USER_ID, account.GetHashedEmail());
var version = await apiClient
.Version.Get(receiveInfo.SelectedVersionId, receiveInfo.ProjectId, cancellationToken)
.ConfigureAwait(false);
using var transport = _serverTransportFactory.Create(account, receiveInfo.ProjectId);
double? previousPercentage = null;
_progressDisplayManager.Begin();
Base commitObject = await _operations
.Receive2(
new Uri(account.serverInfo.url),
receiveInfo.ProjectId,
version.referencedObject,
account.token,
onProgressAction: new PassthroughProgress(args =>
{
if (args.ProgressEvent == ProgressEvent.CacheCheck || args.ProgressEvent == ProgressEvent.DownloadBytes)
{
switch (args.ProgressEvent)
{
case ProgressEvent.CacheCheck:
previousPercentage = _progressDisplayManager.CalculatePercentage(args);
break;
}
}
if (!_progressDisplayManager.ShouldUpdate())
{
return;
}
switch (args.ProgressEvent)
{
case ProgressEvent.CacheCheck:
case ProgressEvent.DownloadBytes:
onOperationProgressed.Report(new("Checking and Downloading... ", previousPercentage));
break;
case ProgressEvent.DeserializeObject:
onOperationProgressed.Report(new("Deserializing ...", _progressDisplayManager.CalculatePercentage(args)));
break;
}
}),
cancellationToken: cancellationToken
)
.ConfigureAwait(false);
await apiClient
.Version.Received(new(version.id, receiveInfo.ProjectId, receiveInfo.SourceApplication), cancellationToken)
.ConfigureAwait(false);
return commitObject;
}
}
@@ -0,0 +1,69 @@
using Speckle.Connectors.Common.Operations;
using Speckle.Sdk.Api;
using Speckle.Sdk.Api.GraphQL.Models;
using Speckle.Sdk.Common;
using Version = Speckle.Sdk.Api.GraphQL.Models.Version;
namespace Speckle.Connectors.Grasshopper8.HostApp;
public abstract record SpeckleUrlModelResource(string Server, string ProjectId)
{
public abstract Task<ReceiveInfo> GetReceiveInfo(Client client, CancellationToken cancellationToken = default);
}
public record SpeckleUrlLatestModelVersionResource(string Server, string ProjectId, string ModelId)
: SpeckleUrlModelResource(Server, ProjectId)
{
public override async Task<ReceiveInfo> GetReceiveInfo(Client client, CancellationToken cancellationToken = default)
{
Project project = await client.Project.Get(ProjectId, cancellationToken).ConfigureAwait(false);
ModelWithVersions model = await client
.Model.GetWithVersions(ModelId, ProjectId, 1, null, null, cancellationToken)
.ConfigureAwait(false);
Version version = model.versions.items[0];
var info = new ReceiveInfo(
client.Account.id,
new Uri(Server),
ProjectId,
project.name,
ModelId,
model.name,
version.id,
version.sourceApplication.NotNull()
);
return info;
}
}
public record SpeckleUrlModelVersionResource(string Server, string ProjectId, string ModelId, string VersionId)
: SpeckleUrlModelResource(Server, ProjectId)
{
public override async Task<ReceiveInfo> GetReceiveInfo(Client client, CancellationToken cancellationToken = default)
{
Project project = await client.Project.Get(ProjectId, cancellationToken).ConfigureAwait(false);
Model model = await client.Model.Get(ModelId, ProjectId, cancellationToken).ConfigureAwait(false);
Version version = await client.Version.Get(VersionId, ProjectId, cancellationToken).ConfigureAwait(false);
var info = new ReceiveInfo(
client.Account.id,
new Uri(Server),
ProjectId,
project.name,
ModelId,
model.name,
VersionId,
version.sourceApplication.NotNull()
);
return info;
}
}
public record SpeckleUrlModelObjectResource(string Server, string ProjectId, string ObjectId)
: SpeckleUrlModelResource(Server, ProjectId)
{
public override Task<ReceiveInfo> GetReceiveInfo(Client client, CancellationToken cancellationToken = default) =>
throw new NotImplementedException("Object Resources are not supported yet");
}
@@ -0,0 +1,82 @@
using System.Text.RegularExpressions;
using Speckle.Sdk;
namespace Speckle.Connectors.Grasshopper8.HostApp;
public record SpeckleResourceBuilder
{
/// <summary>
/// The ReGex pattern to determine if a URL's AbsolutePath is a Frontend2 URL or not.
/// </summary>
private static readonly Regex s_fe2UrlRegex =
new(
@"/projects/(?<projectId>[\w\d]+)(?:/models/(?<model>[\w\d]+(?:@[\w\d]+)?)(?:,(?<additionalModels>[\w\d]+(?:@[\w\d]+)?))*)?"
);
public static SpeckleUrlModelResource[] FromUrlString(string speckleModel)
{
var uri = new Uri(speckleModel);
var serverUrl = uri.GetLeftPart(UriPartial.Authority);
var match = s_fe2UrlRegex.Match(speckleModel);
var result = ParseFe2RegexMatch(serverUrl, match);
return result;
}
private static SpeckleUrlModelResource[] ParseFe2RegexMatch(string serverUrl, Match match)
{
var projectId = match.Groups["projectId"];
var model = match.Groups["model"];
var additionalModels = match.Groups["additionalModels"];
if (!projectId.Success)
{
throw new SpeckleException("The provided url is not a valid Speckle url");
}
if (!model.Success)
{
throw new SpeckleException("The provided url is not pointing to any model in the project.");
}
if (model.Value == "all")
{
throw new NotSupportedException("Fetching all models is not supported.");
}
if (model.Value.StartsWith("$"))
{
throw new NotSupportedException("Federation model urls are not supported");
}
var modelRes = GetUrlModelResource(serverUrl, projectId.Value, model.Value);
var result = new List<SpeckleUrlModelResource> { modelRes };
if (additionalModels.Success)
{
foreach (Capture additionalModelsCapture in additionalModels.Captures)
{
var extraModel = GetUrlModelResource(serverUrl, projectId.Value, additionalModelsCapture.Value);
result.Add(extraModel);
}
}
return result.ToArray();
}
private static SpeckleUrlModelResource GetUrlModelResource(string serverUrl, string projectId, string modelValue)
{
if (modelValue.Length == 32)
{
return new SpeckleUrlModelObjectResource(serverUrl, projectId, modelValue); // Model value is an ObjectID
}
if (!modelValue.Contains('@'))
{
return new SpeckleUrlLatestModelVersionResource(serverUrl, projectId, modelValue); // Model has no version attached
}
var res = modelValue.Split('@');
return new SpeckleUrlModelVersionResource(serverUrl, projectId, res[0], res[1]);
}
}
@@ -0,0 +1,82 @@
using Grasshopper.Kernel.Types;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
namespace Speckle.Connectors.Grasshopper8.Parameters;
public class SpeckleCollectionGoo : GH_Goo<Collection>
{
// TODO: Massive hack for setup only!!! We need some sort of `ShallowCopy` or a transparent wrapper for Speckle Objects
// to prevent backwards propagation of changes of the same instance.
public override IGH_Goo Duplicate() => new SpeckleCollectionGoo { Value = m_value };
public override string ToString() => $"Speckle Collection [{m_value.name}]";
public override bool IsValid => true;
public override string TypeName => "SpeckleCollection";
public override string TypeDescription => "A Speckle Collection";
public override bool CastFrom(object source)
{
Collection? obj = null;
switch (source)
{
case Collection speckleCollection:
obj = speckleCollection;
break;
case SpeckleObjectGoo speckleObjectGoo:
if (speckleObjectGoo.Value is Collection collection)
{
obj = collection;
}
break;
case SpeckleCollectionGoo speckleCollectionGoo:
obj = speckleCollectionGoo.Value;
break;
case GH_Goo<ISpeckleObject> speckleObjectGoo:
if (speckleObjectGoo.Value is Collection collection2)
{
obj = collection2;
}
break;
default:
obj = null;
break;
}
if (obj is null)
{
return false;
}
Value = obj;
return true;
}
public override bool CastTo<TOut>(ref TOut target)
{
var type = typeof(TOut);
var success = false;
if (type == typeof(SpeckleObjectGoo))
{
target = (TOut)(object)new SpeckleObjectGoo { Value = Value };
success = true;
}
else if (type == typeof(SpeckleCollectionGoo))
{
target = (TOut)(object)new SpeckleObjectGoo { Value = Value };
success = true;
}
else if (type == typeof(Collection))
{
target = (TOut)(object)Value;
success = true;
}
else if (type == typeof(Base))
{
target = (TOut)(object)Value;
success = true;
}
return success;
}
}
@@ -0,0 +1,23 @@
using Grasshopper.Kernel;
using Speckle.Connectors.Grasshopper8.HostApp;
namespace Speckle.Connectors.Grasshopper8.Parameters;
public class SpeckleCollectionParam : GH_Param<SpeckleCollectionGoo>
{
public SpeckleCollectionParam()
: this(GH_ParamAccess.item) { }
public SpeckleCollectionParam(IGH_InstanceDescription tag)
: base(tag) { }
public SpeckleCollectionParam(IGH_InstanceDescription tag, GH_ParamAccess access)
: base(tag, access) { }
public SpeckleCollectionParam(GH_ParamAccess access)
: base("Speckle Collection", "SpcklCol", "XXX", "Speckle", "Params", access) { }
public override Guid ComponentGuid => new("F397D941-6B4D-4143-B535-A11F7F776BA1");
protected override Bitmap Icon => BitmapBuilder.CreateHexagonalBitmap("C");
}
@@ -0,0 +1,60 @@
using Grasshopper.Kernel.Types;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
namespace Speckle.Connectors.Grasshopper8.Parameters;
public class SpeckleObjectGoo : GH_Goo<Base>
{
// TODO: Massive hack for setup only!!! We need some sort of `ShallowCopy` or a transparent wrapper for Speckle Objects
// to prevent backwards propagation of changes of the same instance.
public override IGH_Goo Duplicate() => new SpeckleObjectGoo { Value = m_value };
public override string ToString() => $"Speckle Object [{m_value.GetType().Name}]";
public override bool IsValid => true;
public override string TypeName => "SpeckleObject";
public override string TypeDescription => "A Speckle Object";
public override bool CastFrom(object source)
{
Base? obj = source switch
{
Base speckleObject => speckleObject,
SpeckleObjectGoo speckleObjectGoo => speckleObjectGoo.Value,
SpeckleCollectionGoo speckleCollectionGoo => speckleCollectionGoo.Value,
GH_Goo<Base> speckleObjectGoo => speckleObjectGoo.Value,
_ => null
};
if (obj is null)
{
return false;
}
Value = obj;
return true;
}
public override bool CastTo<TOut>(ref TOut target)
{
var type = typeof(TOut);
var success = false;
if (type == typeof(SpeckleObjectGoo))
{
target = (TOut)(object)new SpeckleObjectGoo { Value = Value };
success = true;
}
else if (type == typeof(SpeckleCollectionGoo) && Value is Collection collection)
{
target = (TOut)(object)new SpeckleObjectGoo { Value = collection };
success = true;
}
else if (type == typeof(Base))
{
target = (TOut)(object)Value;
success = true;
}
return success;
}
}
@@ -0,0 +1,20 @@
using Grasshopper.Kernel;
namespace Speckle.Connectors.Grasshopper8.Parameters;
public class SpeckleObjectParam : GH_Param<SpeckleObjectGoo>
{
public SpeckleObjectParam()
: this(GH_ParamAccess.item) { }
public SpeckleObjectParam(IGH_InstanceDescription tag)
: base(tag) { }
public SpeckleObjectParam(IGH_InstanceDescription tag, GH_ParamAccess access)
: base(tag, access) { }
public SpeckleObjectParam(GH_ParamAccess access)
: base("Speckle Object", "SpklObj", "XXXXX", "Speckle", "Params", access) { }
public override Guid ComponentGuid => new("F708F88C-FE00-44EF-8D30-02AB6CF5F728");
}
@@ -0,0 +1,40 @@
using Grasshopper.Kernel.Types;
using Speckle.Connectors.Grasshopper8.HostApp;
namespace Speckle.Connectors.Grasshopper8.Parameters;
public class SpeckleUrlModelResourceGoo : GH_Goo<SpeckleUrlModelResource>
{
public override IGH_Goo Duplicate() => new SpeckleUrlModelResourceGoo() { Value = Value };
public override string ToString() => Value.ToString();
public override bool IsValid => true;
public override string TypeName => "SpeckleUrlModelResource";
public override string TypeDescription => "Points to a model/version/object in a Speckle server";
public override bool CastFrom(object source)
{
switch (source)
{
case SpeckleUrlModelResource resource:
Value = resource;
return true;
default:
return false;
}
}
public override bool CastTo<TOut>(ref TOut target)
{
var type = typeof(TOut);
var success = false;
if (type == typeof(SpeckleUrlModelResource))
{
target = (TOut)(object)Value;
success = true;
}
return success;
}
}
@@ -0,0 +1,20 @@
using Grasshopper.Kernel;
namespace Speckle.Connectors.Grasshopper8.Parameters;
public class SpeckleUrlModelResourceParam : GH_Param<SpeckleUrlModelResourceGoo>
{
public SpeckleUrlModelResourceParam()
: this(GH_ParamAccess.item) { }
public SpeckleUrlModelResourceParam(IGH_InstanceDescription tag)
: base(tag) { }
public SpeckleUrlModelResourceParam(IGH_InstanceDescription tag, GH_ParamAccess access)
: base(tag, access) { }
public SpeckleUrlModelResourceParam(GH_ParamAccess access)
: base("Speckle URL", "spcklUrl", "A Speckle resource", "Speckle", "Resources", access) { }
public override Guid ComponentGuid => new Guid("E5421FC2-F10D-447F-BF23-5C934ABDB2D3");
}
@@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection;
using Speckle.Connectors.Common;
using Speckle.Connectors.Common.Builders;
using Speckle.Connectors.Common.Operations.Receive;
using Speckle.Connectors.Grasshopper8.Operations.Receive;
using Speckle.Connectors.Grasshopper8.HostApp;
using Speckle.Converters.Rhino;
using Speckle.Sdk;
using Speckle.Sdk.Credentials;
@@ -26,6 +26,7 @@ public class PriorityLoader : GH_AssemblyPriority
services.AddRhinoConverters().AddConnectorUtils();
services.AddTransient<IHostObjectBuilder, GrasshopperHostObjectBuilder>();
services.AddTransient<GrasshopperReceiveOperation>();
services.AddSingleton(DefaultTraversal.CreateTraversalFunc());
services.AddTransient<TraversalContextUnpacker>();
services.AddTransient<AccountManager>();
@@ -30,8 +30,4 @@
<ProjectReference Include="..\..\..\Converters\Rhino\Speckle.Converters.Rhino8\Speckle.Converters.Rhino8.csproj" />
<ProjectReference Include="..\..\..\Sdk\Speckle.Connectors.Common\Speckle.Connectors.Common.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="HostApp\" />
</ItemGroup>
</Project>
@@ -1,32 +0,0 @@
using Grasshopper.Kernel;
using Grasshopper.Kernel.Types;
using Speckle.Sdk.Models;
namespace Speckle.Connectors.Grasshopper8;
public class SpeckleObjectParam : GH_Param<SpeckleObjectGoo>
{
public SpeckleObjectParam(IGH_InstanceDescription tag)
: base(tag) { }
public SpeckleObjectParam(IGH_InstanceDescription tag, GH_ParamAccess access)
: base(tag, access) { }
public SpeckleObjectParam(GH_ParamAccess access)
: base("Speckle Object", "SpklObj", "XXXXX", "Speckle", "Params", access) { }
public override Guid ComponentGuid => new("F708F88C-FE00-44EF-8D30-02AB6CF5F728");
}
public class SpeckleObjectGoo : GH_Goo<ISpeckleObject>
{
// TODO: Massive hack for setup only!!! We need some sort of `ShallowCopy` or a transparent wrapper for Speckle Objects
// to prevent backwards propagation of changes of the same instance.
public override IGH_Goo Duplicate() => new SpeckleObjectGoo { Value = m_value };
public override string ToString() => m_value.ToString();
public override bool IsValid => true;
public override string TypeName => "SpeckleObject";
public override string TypeDescription => "A Speckle Object";
}
@@ -273,9 +273,36 @@
"Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )"
}
},
"speckle.connectors.dui": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Connectors.Common": "[1.0.0, )",
"Speckle.Sdk": "[3.1.0-dev.191, )",
"Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )",
"System.Threading.Tasks.Dataflow": "[6.0.0, )"
}
},
"speckle.connectors.dui.webview": {
"type": "Project",
"dependencies": {
"Microsoft.Web.WebView2": "[1.0.1938.49, )",
"Speckle.Connectors.DUI": "[1.0.0, )"
}
},
"speckle.connectors.logging": {
"type": "Project"
},
"speckle.connectors.rhino7": {
"type": "Project",
"dependencies": {
"RhinoCommon": "[7.13.21348.13001, )",
"RhinoWindows": "[7.13.21348.13001, )",
"Speckle.Connectors.Common": "[1.0.0, )",
"Speckle.Connectors.DUI.WebView": "[1.0.0, )",
"Speckle.Converters.Rhino7": "[1.0.0, )"
}
},
"speckle.converters.common": {
"type": "Project",
"dependencies": {
@@ -283,6 +310,13 @@
"Speckle.Objects": "[3.1.0-dev.191, )"
}
},
"speckle.converters.rhino7": {
"type": "Project",
"dependencies": {
"RhinoCommon": "[7.13.21348.13001, )",
"Speckle.Converters.Common": "[1.0.0, )"
}
},
"speckle.converters.rhino8": {
"type": "Project",
"dependencies": {
@@ -323,6 +357,21 @@
"resolved": "2.2.0",
"contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A=="
},
"Microsoft.Web.WebView2": {
"type": "CentralTransitive",
"requested": "[1.0.1938.49, )",
"resolved": "1.0.1938.49",
"contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw=="
},
"RhinoWindows": {
"type": "CentralTransitive",
"requested": "[8.9.24194.18121, )",
"resolved": "7.13.21348.13001",
"contentHash": "V94T8emmJmFfmbd5cu+uTNS0neZApx1Q5MXvsQGFtt/mEGEbdHE+dFOETNgbOOJXSdNboAnCR3uo0GosOFX+/g==",
"dependencies": {
"RhinoCommon": "[7.13.21348.13001]"
}
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.1.0-dev.191, )",
@@ -354,6 +403,12 @@
"requested": "[3.1.0-dev.191, )",
"resolved": "3.1.0-dev.191",
"contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q=="
},
"System.Threading.Tasks.Dataflow": {
"type": "CentralTransitive",
"requested": "[6.0.0, )",
"resolved": "6.0.0",
"contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA=="
}
}
}
+1 -1
View File
@@ -31,7 +31,7 @@
<!-- Logging -->
CA1848;CA2254;CA1727;
<!-- Others we don't want -->
CA1815;CA1725;
CA1815;CA1725;CA1501;
<!-- Package using wrong RIDs (Net8 changed them). Usually fixable by updating. -->
NETSDK1206;
$(NoWarn)