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