Hi guys,
hope you are doing well there in London!
I am developing some C# code atm and want to send some data to https://hestia.speckle.works.
I have an account, a JWT token and I managed to add SpeckleCore to my dependencies.
Now I am struggling a bit to get started and looking into SpeckleRhino as an example seems a bit over the top.
So, is there some simple boilerplate example in C# of how to login, send, receive, etc. some data?
Or maybe you have any other hints on how to get started with SpeckleCore?
Yeah, I am pretty happy to be finally able to do some coding, especially with Speckle
So my data looks something like this atm:
public class Node
{
public int id;
public float x;
public float y;
public float z;
}
public class Quad
{
public int id;
public Node[] nodes;
public int group;
public float vx;
public float vy;
public float nx;
public float ny;
public float nxy;
public float sigx;
public float sigy;
public float tau;
public int iteration;
}
My object model is probably gonna change this afternoon already, but it´s basically a finite element mesh with nodes and shell elements and some results attached to it.
edit: sorry, I don´t know where the line breaks went…
Okay, backtracking a bit, you do know there’s a bunch of Arup structural classes here that you can create with the schema builder components here, that do support quads afaik, and then you can also spin them online and colour them by their results.
That aside, those look fine, and they’ll probably pass natively as abstract objects. I’ll try and hack an example after lunch, or now. There’s two approaches:
if you’re creating those objects in a c# script in grasshopper, you can probably just plop them into a sender, and it should work.
if you want to send data from your c# script (is it in grasshopper?) i’ll write down a minimal example!
I am reading results from Sofistik and thus I created a console application in Visual Studio.
The idea is to do some post-processing with the data and then feeding them back into the next iteration in Sofistik.
That´s why I want to stick close to Sofistik´s data model. But I´ll try to use some existing classes!
So, it works for my a little example with around 100 nodes and quads.
In my production case I have about 70000 nodes and quads though…
… and get an exception after 2 seconds: One or more errors occurred.
It’s not a problem: you need to orchestrate the requests by saving objects separately first and then referencing them in the stream. I’ll write an example later.
Nevertheless, there’s a prior question then: saving 70k nodes individually is not the most effective way of dealing with this - are you going to need them separately? This sounds much more approachable as a 70k vertex mesh with quads (or 7 * 10k verts meshes), and some separate per quad props. Typed arrays are the way to go!
Having a bit of a flashback: has an identical discussion with @mishaelnuh when dealing with gsa analysis result meshes.
I’ll add a section on how to save many objects - hopefully before lunch; you can check the GH/rhino implementation if curious, they deal with this scenario.
Yeps. @tlmn, I’ve just started writing a generic method to send many objects; it probably won’t be the best for your specific use case.
I’ll also add a NodeArray speckle object of sorts as an example of how to best save large amounts of simple data - the nodes just have, at the end, three coordinate props.
And if I manage to steal more time, a way to get many objects too.
/// <summary>
/// Orchestrates the saving of many objects.
/// </summary>
/// <param name="account"></param>
/// <param name="objects"></param>
/// <returns></returns>
static IEnumerable<SpecklePlaceholder> SaveManyObjects( Account account, IEnumerable<SpeckleObject> objects )
{
Console.WriteLine( String.Format( "Saving {0} objects.", objects.Count() ) );
Console.WriteLine();
Console.WriteLine();
// Step 1: Payload creation.
// The approach below keeps request sizes around 500kb each.
// NOTE: Will change in Speckle 2.0
var objectUpdatePayloads = new List<List<SpeckleObject>>();
long totalBucketSize = 0, currentBucketSize = 0;
var currentBucketObjects = new List<SpeckleObject>();
var allObjects = new List<SpeckleObject>();
foreach ( var obj in objects )
{
long size = Converter.getBytes( obj ).Length;
currentBucketSize += size;
totalBucketSize += size;
currentBucketObjects.Add( obj );
if ( currentBucketSize > 5e5 ) // restrict max to ~500kb;
{
objectUpdatePayloads.Add( currentBucketObjects );
currentBucketObjects = new List<SpeckleObject>();
currentBucketSize = 0;
}
}
// add in the last bucket
if ( currentBucketObjects.Count > 0 )
{
objectUpdatePayloads.Add( currentBucketObjects );
}
Console.WriteLine();
Console.WriteLine( String.Format( "Done making payloads ({0} total).", objectUpdatePayloads.Count ) );
// Step 2: Actually persist the objects, and return placeholders with their ObjectIds.
// This might take a while.
var client = new SpeckleApiClient( account.RestApi, false, "console_app" );
client.AuthToken = account.Token;
var i = 0;
var totalObjs = 0;
foreach ( var payload in objectUpdatePayloads )
{
totalObjs += payload.Count;
Console.Write( String.Format( "Sending payload #{0} ({1} objects, total saved {2}) ...", i++, payload.Count, totalObjs ) );
var result = client.ObjectCreateAsync( payload ).Result.Resources;
foreach ( var placehholder in result )
yield return placehholder as SpecklePlaceholder;
Console.Write( " done." );
Console.CursorLeft = 0;
}
}
There’s two main steps in there, namely:
create a bunch of payloads based on the object sizes, restricting them to ~500kb (magic number).
send those payloads to the server, and yield return object placeholders.
An important note: this does not use any localcontext caching, bypassing any diffing benefits you might have from not sending previously sent objects. That’s another subject, but the existing implementations all make use of it.
There’s some extra optimisations I’m itching to do in the code above, but for now that should suffice
Very cool, it seems to work all fine!
I am trying to make use of the SpeckleStructural classes now, but i am struggling a bit to create a mesh. Maybe there is a boilerplate example for this as well?
I created some structural nodes so far…
SpecklePoint specklePoint = new SpecklePoint { Value = { node.x, node.y, node.z } };
StructuralNode structuralNode = new StructuralNode { basePoint = specklePoint };
The SpeckleMesh object asks for vertices and faces, but I have no idea what they are supposed to look like…
just wanted to spin up some old speckle code and run into an exception.
System.MissingMethodException
HResult=0x80131513
Message=Method not found: ‘Void SQLite.SQLiteConnection…ctor(System.String, Boolean, System.Object)’.
Source=SpeckleCore
StackTrace:
at SpeckleCore.LocalContext.Init()
at SpeckleCore.SpeckleInitializer.Initialize(String pathToKits)
at SpkConsole.Program.Main(String[] args) in C:\Users\tilman.reinhardt\git\SpkConsole\Program.cs:line 15