public void BakeLayer(string layerId) { SpeckleCore.Layer myLayer = Client.Stream.Layers.FirstOrDefault(l => l.Guid == layerId); // create or get parent string parent = String.Format("{1} | {0}", Client.Stream.StreamId, Client.Stream.Name); var parentId = Rhino.RhinoDoc.ActiveDoc.Layers.FindByFullPath(parent, true); if (parentId == -1) { var parentLayer = new Rhino.DocObjects.Layer() { Color = System.Drawing.Color.Black, Name = parent }; parentId = Rhino.RhinoDoc.ActiveDoc.Layers.Add(parentLayer); } else { int prev = Rhino.RhinoDoc.ActiveDoc.Layers.FindByFullPath(parent + "::" + myLayer.Name, true); if (prev != -1) { Rhino.RhinoDoc.ActiveDoc.Layers.Purge(prev, true); } } int theLayerId = Rhino.RhinoDoc.ActiveDoc.Layers.FindByFullPath(parent + "::" + myLayer.Name, true); if (theLayerId == -1) { var layer = new Rhino.DocObjects.Layer() { Name = myLayer.Name, Id = Guid.Parse(myLayer.Guid), ParentLayerId = Rhino.RhinoDoc.ActiveDoc.Layers[parentId].Id, Color = GetColorFromLayer(myLayer), IsVisible = true }; var index = Rhino.RhinoDoc.ActiveDoc.Layers.Add(layer); for (int i = ( int )myLayer.StartIndex; i < myLayer.StartIndex + myLayer.ObjectCount; i++) { if (Display.Geometry[i] != null) { Rhino.RhinoDoc.ActiveDoc.Objects.Add(Display.Geometry[i], new ObjectAttributes() { LayerIndex = index }); } } } Rhino.RhinoDoc.ActiveDoc?.Views.Redraw(); }
public void ToggleLayerVisibility(string layerId, bool status) { SpeckleCore.Layer myLayer = Client.Stream.Layers.FirstOrDefault(l => l.Guid == layerId); if (myLayer == null) { throw new Exception("Bloopers. Layer not found."); } for (int i = ( int )myLayer.StartIndex; i < myLayer.StartIndex + myLayer.ObjectCount; i++) { Display.VisibleList[i] = status; } Rhino.RhinoDoc.ActiveDoc?.Views.Redraw(); }
public System.Drawing.Color GetColorFromLayer(SpeckleCore.Layer layer) { System.Drawing.Color layerColor = System.Drawing.ColorTranslator.FromHtml("#AEECFD"); try { if (layer != null && layer.Properties != null) { layerColor = System.Drawing.ColorTranslator.FromHtml(layer.Properties.Color.Hex); } } catch { Debug.WriteLine("Layer '{0}' had no assigned color", layer.Name); } return(layerColor); }
public void ToggleLayerHover(string layerId, bool status) { SpeckleCore.Layer myLayer = Client.Stream.Layers.FirstOrDefault(l => l.Guid == layerId); if (myLayer == null) { throw new Exception("Bloopers. Layer not found."); } if (status) { Display.HoverRange = new Interval(( double )myLayer.StartIndex, ( double )(myLayer.StartIndex + myLayer.ObjectCount)); } else { Display.HoverRange = null; } Rhino.RhinoDoc.ActiveDoc?.Views.Redraw(); }
public async void SendStaggeredUpdate(bool force = false) { if (Paused && !force) { Context.NotifySpeckleFrame("client-expired", StreamId, ""); return; } else { // create a clone var cloneResult = Client.StreamCloneAsync(StreamId).Result; Client.Stream.Children.Add(cloneResult.Clone.StreamId); Client.BroadcastMessage("stream", StreamId, new { eventType = "update-children" }); } if (IsSendingUpdate) { Expired = true; return; } IsSendingUpdate = true; Context.NotifySpeckleFrame("client-is-loading", StreamId, ""); var objs = RhinoDoc.ActiveDoc.Objects.FindByUserString("spk_" + this.StreamId, "*", false).OrderBy(obj => obj.Attributes.LayerIndex); Context.NotifySpeckleFrame("client-progress-message", StreamId, "Converting " + objs.Count() + " objects..."); // layer list creation var pLayers = new List <SpeckleCore.Layer>(); int lindex = -1, count = 0, orderIndex = 0; foreach (RhinoObject obj in objs) { Rhino.DocObjects.Layer layer = RhinoDoc.ActiveDoc.Layers[obj.Attributes.LayerIndex]; if (lindex != obj.Attributes.LayerIndex) { var spkLayer = new SpeckleCore.Layer() { Name = layer.FullPath, Guid = layer.Id.ToString(), ObjectCount = 1, StartIndex = count, OrderIndex = orderIndex++, Properties = new LayerProperties() { Color = new SpeckleCore.SpeckleBaseColor() { A = 1, Hex = System.Drawing.ColorTranslator.ToHtml(layer.Color) }, } }; pLayers.Add(spkLayer); lindex = obj.Attributes.LayerIndex; } else { var spkl = pLayers.FirstOrDefault(pl => pl.Name == layer.FullPath); spkl.ObjectCount++; } count++; } // convert objects var convertedObjects = new List <SpeckleObject>(); foreach (RhinoObject obj in objs) { var myObj = Converter.Serialise(obj.Geometry); myObj.ApplicationId = obj.Id.ToString(); convertedObjects.Add(myObj); } LocalContext.PruneExistingObjects(convertedObjects, Client.BaseUrl); List <SpeckleObject> persistedObjects = new List <SpeckleObject>(); if (convertedObjects.Count(obj => obj.Type == "Placeholder") != convertedObjects.Count) { // create the update payloads count = 0; var objectUpdatePayloads = new List <List <SpeckleObject> >(); long totalBucketSize = 0; long currentBucketSize = 0; var currentBucketObjects = new List <SpeckleObject>(); var allObjects = new List <SpeckleObject>(); foreach (SpeckleObject convertedObject in convertedObjects) { if (count++ % 100 == 0) { Context.NotifySpeckleFrame("client-progress-message", StreamId, "Converted " + count + " objects out of " + objs.Count() + "."); } // size checking & bulk object creation payloads creation long size = Converter.getBytes(convertedObject).Length; currentBucketSize += size; totalBucketSize += size; currentBucketObjects.Add(convertedObject); // Object is too big? if (size > 2e6) { Context.NotifySpeckleFrame("client-error", StreamId, JsonConvert.SerializeObject("This stream contains a super big object. These will fail. Sorry for the bad error message - we're working on improving this.")); currentBucketObjects.Remove(convertedObject); } if (currentBucketSize > 5e5) // restrict max to ~500kb; should it be user config? anyway these functions should go into core. at one point. { Debug.WriteLine("Reached payload limit. Making a new one, current #: " + objectUpdatePayloads.Count); objectUpdatePayloads.Add(currentBucketObjects); currentBucketObjects = new List <SpeckleObject>(); currentBucketSize = 0; } } // add in the last bucket if (currentBucketObjects.Count > 0) { objectUpdatePayloads.Add(currentBucketObjects); } Debug.WriteLine("Finished, payload object update count is: " + objectUpdatePayloads.Count + " total bucket size is (kb) " + totalBucketSize / 1000); // create bulk object creation tasks int k = 0; List <ResponseObject> responses = new List <ResponseObject>(); foreach (var payload in objectUpdatePayloads) { Context.NotifySpeckleFrame("client-progress-message", StreamId, String.Format("Sending payload {0} out of {1}", k++, objectUpdatePayloads.Count)); try { var objResponse = await Client.ObjectCreateAsync(payload); responses.Add(objResponse); persistedObjects.AddRange(objResponse.Resources); int m = 0; foreach (var oL in payload) { oL._id = objResponse.Resources[m++]._id; } // push sent objects in the cache non-blocking Task.Run(() => { foreach (var oL in payload) { if (oL.Type != "Placeholder") { LocalContext.AddSentObject(oL, Client.BaseUrl); } } }); } catch (Exception err) { Context.NotifySpeckleFrame("client-error", Client.Stream.StreamId, JsonConvert.SerializeObject(err.Message)); Context.NotifySpeckleFrame("client-done-loading", StreamId, ""); IsSendingUpdate = false; return; } } } else { persistedObjects = convertedObjects; } Context.NotifySpeckleFrame("client-progress-message", StreamId, "Updating stream..."); // finalise layer creation foreach (var layer in pLayers) { layer.Topology = "0-" + layer.ObjectCount + " "; } // create placeholders for stream update payload List <SpeckleObject> placeholders = new List <SpeckleObject>(); //foreach ( var myResponse in responses ) foreach (var obj in persistedObjects) { placeholders.Add(new SpecklePlaceholder() { _id = obj._id }); } // create stream update payload SpeckleStream streamUpdatePayload = new SpeckleStream(); streamUpdatePayload.Layers = pLayers; streamUpdatePayload.Objects = placeholders; streamUpdatePayload.Name = Client.Stream.Name; // set some base properties (will be overwritten) var baseProps = new Dictionary <string, object>(); baseProps["units"] = RhinoDoc.ActiveDoc.ModelUnitSystem.ToString(); baseProps["tolerance"] = RhinoDoc.ActiveDoc.ModelAbsoluteTolerance; baseProps["angleTolerance"] = RhinoDoc.ActiveDoc.ModelAngleToleranceRadians; streamUpdatePayload.BaseProperties = baseProps; // update the stream ResponseBase response = null; try { response = await Client.StreamUpdateAsync(Client.Stream.StreamId, streamUpdatePayload); } catch (Exception err) { Context.NotifySpeckleFrame("client-error", Client.Stream.StreamId, JsonConvert.SerializeObject(err.Message)); IsSendingUpdate = false; return; } // emit events, etc. Client.Stream.Layers = streamUpdatePayload.Layers.ToList(); Client.Stream.Objects = placeholders; Context.NotifySpeckleFrame("client-metadata-update", StreamId, Client.Stream.ToJson()); Context.NotifySpeckleFrame("client-done-loading", StreamId, ""); Client.BroadcastMessage("stream", StreamId, new { eventType = "update-global" }); IsSendingUpdate = false; if (Expired) { DataSender.Start(); } Expired = false; }
// TODO: This method, or an abstracted version of it, should move to Speckle Core. public async void SendStaggeredUpdate(bool force = false) { if (Paused && !force) { Context.NotifySpeckleFrame("client-expired", StreamId, ""); return; } if (IsSendingUpdate) { Expired = true; return; } IsSendingUpdate = true; Context.NotifySpeckleFrame("client-is-loading", StreamId, ""); var objs = RhinoDoc.ActiveDoc.Objects.FindByUserString("spk_" + this.StreamId, "*", false).OrderBy(obj => obj.Attributes.LayerIndex); Context.NotifySpeckleFrame("client-progress-message", StreamId, "Converting " + objs.Count() + " objects..."); List <SpeckleCore.Layer> pLayers = new List <SpeckleCore.Layer>(); List <SpeckleObject> convertedObjects = new List <SpeckleObject>(); List <List <SpeckleObject> > objectUpdatePayloads = new List <List <SpeckleObject> >(); long totalBucketSize = 0; long currentBucketSize = 0; List <SpeckleObject> currentBucketObjects = new List <SpeckleObject>(); List <SpeckleObject> allObjects = new List <SpeckleObject>(); int lindex = -1, count = 0, orderIndex = 0; foreach (RhinoObject obj in objs) { // layer list creation Rhino.DocObjects.Layer layer = RhinoDoc.ActiveDoc.Layers[obj.Attributes.LayerIndex]; if (lindex != obj.Attributes.LayerIndex) { var spkLayer = new SpeckleCore.Layer() { Name = layer.FullPath, Guid = layer.Id.ToString(), ObjectCount = 1, StartIndex = count, OrderIndex = orderIndex++, Properties = new LayerProperties() { Color = new SpeckleCore.SpeckleBaseColor() { A = 1, Hex = System.Drawing.ColorTranslator.ToHtml(layer.Color) }, } }; pLayers.Add(spkLayer); lindex = obj.Attributes.LayerIndex; } else { var spkl = pLayers.FirstOrDefault(pl => pl.Name == layer.FullPath); spkl.ObjectCount++; } count++; // object conversion SpeckleObject convertedObject; convertedObject = Converter.Serialise(obj.Geometry); convertedObject.ApplicationId = obj.Id.ToString(); allObjects.Add(convertedObject); if (count % 10 == 0) { Context.NotifySpeckleFrame("client-progress-message", StreamId, "Converted " + count + " objects out of " + objs.Count() + "."); } // check cache and see what the response from the server is when sending placeholders // in the ObjectCreateBulkAsyncRoute if (Context.SpeckleObjectCache.ContainsKey(convertedObject.Hash)) { convertedObject = new SpecklePlaceholder() { Hash = convertedObject.Hash, _id = Context.SpeckleObjectCache[convertedObject.Hash]._id, ApplicationId = Context.SpeckleObjectCache[convertedObject.Hash].ApplicationId }; } // size checking & bulk object creation payloads creation long size = Converter.getBytes(convertedObject).Length; currentBucketSize += size; totalBucketSize += size; currentBucketObjects.Add(convertedObject); if (currentBucketSize > 2e6) { // means we're around fooking bazillion mb of an upload. FAIL FAIL FAIL Context.NotifySpeckleFrame("client-error", StreamId, JsonConvert.SerializeObject("This stream contains a super big object. These are not supported yet :(")); Context.NotifySpeckleFrame("client-done-loading", StreamId, ""); IsSendingUpdate = false; return; } if (currentBucketSize > 5e5) // restrict max to ~500kb; should it be user config? anyway these functions should go into core. at one point. { Debug.WriteLine("Reached payload limit. Making a new one, current #: " + objectUpdatePayloads.Count); objectUpdatePayloads.Add(currentBucketObjects); currentBucketObjects = new List <SpeckleObject>(); currentBucketSize = 0; } // catch overflows early if (totalBucketSize >= 50e6) { Context.NotifySpeckleFrame("client-error", StreamId, JsonConvert.SerializeObject("This is a humongous update, in the range of ~50mb. For now, create more streams instead of just one massive one! Updates will be faster and snappier, and you can combine them back together at the other end easier. " + totalBucketSize / 1000 + "(kb)")); IsSendingUpdate = false; Context.NotifySpeckleFrame("client-done-loading", StreamId, ""); return; } } // last bucket if (currentBucketObjects.Count > 0) { objectUpdatePayloads.Add(currentBucketObjects); } Debug.WriteLine("Finished, payload object update count is: " + objectUpdatePayloads.Count + " total bucket size is (kb) " + totalBucketSize / 1000); if (objectUpdatePayloads.Count > 100 || totalBucketSize >= 50e6) { // means we're around fooking bazillion mb of an upload. FAIL FAIL FAIL Context.NotifySpeckleFrame("client-error", StreamId, JsonConvert.SerializeObject("This is a humongous update, in the range of ~50mb. For now, create more streams instead of just one massive one! Updates will be faster and snappier, and you can combine them back together at the other end easier. " + totalBucketSize / 1000 + "(kb)")); IsSendingUpdate = false; Context.NotifySpeckleFrame("client-done-loading", StreamId, ""); return; } // create bulk object creation tasks int k = 0; List <ResponseObject> responses = new List <ResponseObject>(); foreach (var payload in objectUpdatePayloads) { Context.NotifySpeckleFrame("client-progress-message", StreamId, String.Format("Sending payload {0} out of {1}", k++, objectUpdatePayloads.Count)); try { responses.Add(await Client.ObjectCreateAsync(payload)); } catch (Exception err) { Context.NotifySpeckleFrame("client-error", Client.Stream.StreamId, JsonConvert.SerializeObject(err.Message)); Context.NotifySpeckleFrame("client-done-loading", StreamId, ""); IsSendingUpdate = false; return; } } Context.NotifySpeckleFrame("client-progress-message", StreamId, "Updating stream..."); // finalise layer creation foreach (var layer in pLayers) { layer.Topology = "0-" + layer.ObjectCount + " "; } // create placeholders for stream update payload List <SpeckleObject> placeholders = new List <SpeckleObject>(); int m = 0; foreach (var myResponse in responses) { foreach (var obj in myResponse.Resources) { placeholders.Add(new SpecklePlaceholder() { _id = obj._id, ApplicationId = allObjects[m++].ApplicationId }); } } // create stream update payload SpeckleStream streamUpdatePayload = new SpeckleStream(); streamUpdatePayload.Layers = pLayers; streamUpdatePayload.Objects = placeholders; streamUpdatePayload.Name = Client.Stream.Name; // set some base properties (will be overwritten) var baseProps = new Dictionary <string, object>(); baseProps["units"] = RhinoDoc.ActiveDoc.ModelUnitSystem.ToString(); baseProps["tolerance"] = RhinoDoc.ActiveDoc.ModelAbsoluteTolerance; baseProps["angleTolerance"] = RhinoDoc.ActiveDoc.ModelAngleToleranceRadians; streamUpdatePayload.BaseProperties = baseProps; // push it to the server yo! ResponseBase response = null; try { response = await Client.StreamUpdateAsync(Client.Stream.StreamId, streamUpdatePayload); } catch (Exception err) { Context.NotifySpeckleFrame("client-error", Client.Stream.StreamId, JsonConvert.SerializeObject(err.Message)); IsSendingUpdate = false; return; } // put the objects in the cache int l = 0; foreach (var obj in streamUpdatePayload.Objects) { obj._id = placeholders[l]._id; Context.SpeckleObjectCache[allObjects[l].Hash] = placeholders[l]; l++; } // emit events, etc. Client.Stream.Layers = streamUpdatePayload.Layers.ToList(); Client.Stream.Objects = placeholders; Context.NotifySpeckleFrame("client-metadata-update", StreamId, Client.Stream.ToJson()); Context.NotifySpeckleFrame("client-done-loading", StreamId, ""); Client.BroadcastMessage(new { eventType = "update-global" }); IsSendingUpdate = false; if (Expired) { DataSender.Start(); } Expired = false; }
public async void UpdateGlobal() { bRefreshingDisplay = true; var streamGetResponse = await Client.StreamGetAsync(Client.StreamId, null); if (streamGetResponse.Success == false) { Debug.Log(streamGetResponse.Message); // TODO: Actually handle this } Client.Stream = streamGetResponse.Resource; // This is gross of the C# API Debug.Log("Getting objects...."); var getObjectResult = await Client.ObjectGetBulkAsync(Client.Stream.Objects.Select(obj => obj._id).ToArray(), null); // TODO: Check if ObjectGetBulkAsync returns objects in a corresponding order. If it does, the next little bit can be simplified Dictionary <string, SpeckleCore.SpeckleObject> ObjectCache = getObjectResult.Resources.ToDictionary(speckleObject => speckleObject._id); SpeckleObjects = Client.Stream.Objects.Select(speckleObject => ObjectCache[speckleObject._id]).ToList(); // Remove old layers foreach (SpeckleCore.Layer layer in Layers.Keys.Where(layer => Client.Stream.Layers.Where(newLayer => newLayer.Guid != layer.Guid).Count() > 0).ToList()) // ToList is required because we're modifying Layers, I think { Destroy(Layers[layer]); Layers.Remove(layer); } // Add new layers foreach (SpeckleCore.Layer layer in Client.Stream.Layers.Where(layer => !Layers.ContainsKey(layer)).ToList()) { Layers[layer] = new GameObject(layer.Name); Layers[layer].transform.SetParent(rootGameObject.transform); } // Mark all existing objects foreach (UnitySpeckleObjectData usod in rootGameObject.GetComponentsInChildren <UnitySpeckleObjectData>()) { usod.LayerName = null; } // Create new objects for (int i = 0; i < SpeckleObjects.Count; i++) { SpeckleCore.Layer layer = LayerFromIndex(i); GameObject layerObject = Layers[layer]; GameObject gameObject = (GameObject)SpeckleCore.Converter.Deserialise(SpeckleObjects[i]); // TODO: This creates a new game object even if one already exists. It should reuse objects which already exist // TODO: The more fundamental issue is that checking which layer an object is in is tricky. Perhaps layers map more naturally to Unity's tags. gameObject.GetComponent <UnitySpeckleObjectData>().LayerName = layer.Name; gameObject.transform.SetParent(layerObject.transform); } // Destroy all objects which are still marked foreach (UnitySpeckleObjectData usod in rootGameObject.GetComponentsInChildren <UnitySpeckleObjectData>()) { if (usod.LayerName == null) { Destroy(usod.gameObject); } } bRefreshingDisplay = false; transform.GetComponent <UnitySpeckle>().OnUpdateReceived.Invoke(this); }