Detect user text changes to trigger content cache

During the Beta, I could detect changes made to user text in Rhino by comparing the user text content with the user text derived from the geometry in Rhino (by feeding it through a curve component in this example: Detect geometry changes - access GUID data in between parenthesis? - #10 by Intuos):

However, this no longer works as both display the same value and do not synchronise changes from Rhino.


I did notice that when I reattach the wires or duplicate the user text component, that updates the values:

Are there any (other) methods that help me detect changes?

Setting the action to true/ false with a boolean also doesn’t prompt any updates:

Using the trigger component on the content cache leads to Rhino becoming unresponsive.

It seems like triggering the User Text component is the best I can do, though I rather not brute force the updates and just use a boolean value to trigger one.

Likely the best method to detect User Text changes is to trigger User Text updates on a timer to then compare it to the previous values, though as of now I am not quite sure how well this scales on larger datasets.

Hi @Intuos, good to see you again,

The Content Cache component has changed a bit since you used it in beta.

The “Red Down Arrow” indicates you are pushing content to the model and the “Push Content” black button below that is a manual button. Meaning, you will not see updates unless you push that.

If you want continuous, real-time updates, zoom in on the Content Cache component and click the + that appears to expand additional parameters (Or use “Shift+Double Click”) and then hook up a Boolean Toggle to the P input and you should see the real-time updates.

Hope that helps you!

EDIT:

Are you working with Grasshopper geometry or Rhino Geometry that you are referencing?

The Query Model Objects component will update the Content Cache in Real-Time and the User Text will update with that…

If you are only inputting Grasshopper geometry that is being cached in the model but was not referenced from the model then I don’t believe it will update the values by default.

Interesting.

But… If i’m not mistaken, Intuos want to do the opposite: reading/detecting user text whenever they changes. (seen your edit now…)

Problem: editing the actual geometry will trigger referenced params in grasshopper to expire and recompute, but just editing attributes like layer, color, user-texts, will not.

@AndyPayne , there are some component in the new tab that lets one do this?

Hi @michaelvollrath also good to see you again!

I am referencing geometry from Rhino, but since I have not separated out my curves to particular layers (I am only using some curves on a layer and need to rework the others as I go), I’m starting with referenced curves in a curve component. I want to add the attributes I need for the script as user text and use those as scrip input values. So whenever I change the attributes, I need to pull them back into Grasshopper to update the User Text component values. And for that, I need to detect changes in the most efficient way possible as to not bog down the script later on. I might be using this method several times for multiple parts of the script after all.

I guess I might as well tag @kike seeing as he worked on the new Content Cache.

@Intuos how are you referencing the geometry from Rhino?

If you are using the Query Model Objects component, it should be updating the User Text in real-time just fine…

If you have a geometry container such as Geometry or Brep that you “Right Click Set” the references with, I don’t think that will update.

The QMO component will expire the cache to ensure the changes are updated… basically the QMO component “listens” for Rhino Document changes and then expires downstream components when it “hears” something changed. (Please correct me if I’m wrong on that)

So likely, you just need to use a QMO to “get” your referenced Rhino Geometry.

If you already are doing that… then something else is at play

act as some sort of “Geometry pipeline” component.
It’s quite hard to “link” only specific geometries, it should work with guids, but it can’t … (right?).
That’s what guids are made for.

In the meantime a dev will shine some light, i made this…


attributes event expire.gh (18.1 KB)

  private void RunScript(List<Guid> id, ref object ID)
  {
    if(comp == null)comp = this.Component;
    ids = id;
    Rhino.RhinoDoc.ModifyObjectAttributes -= OnModifyObjectAttributes;
    Rhino.RhinoDoc.ModifyObjectAttributes += OnModifyObjectAttributes;
    ID = id;
  }

  // <Custom additional code> 
  static IGH_Component comp;
  static List<Guid> ids;
  public static void OnModifyObjectAttributes(object sender, Rhino.DocObjects.RhinoModifyObjectAttributesEventArgs e){
    bool somethingchanged = false;
    foreach(Guid id in ids){
      if(e.RhinoObject.Id.Equals(id)){
        somethingchanged = true;
        break;
      }
    }
    if(somethingchanged){
      comp.ExpireSolution(true);
    }
  }

The c#script itself will just pass the input data to the output, straight. Guids.
If any rhino object have its attributes changed, and the guid is part of the list, the c# component will expire itself as whole.
Works with lists, trees untested.

Indeed, it does not, hence the trigger component to make it update. Notice that when you plug in the output of the geometry container into a new User Text, the value is updated. This can cause confusion as well as unpredictable scripts.

But it used to be such that when you plug a geometry container into a User Text component, it would reference the Rhino geometry directly and update accordingly. The fact that this is now missing or stopped working is really throwing off my old scripts and makes new scripts that compare Grasshopper attributes to those in Rhino really convoluted (and slower due to having to use multiple Geometry Caches.

Hi @Intuos,

All ‘Query XXX’ components have an option to grab a non synchronized copy of the model objects.

Does this help?

1 Like

Thanks @kike, it’s good to know that this option exists.
But what if I want to use referenced curves in a curve container (so I get the ease of manually picking my geometry and update small parts as I go)? Say I have a bunch of buildings and it’s easier to manually select than to sort a whole lot of unsorted data. I don’t want to resort to curve in curve sorting if I don’t have to as it forfeits ease of use.

Okay, now I got this, but it really starts to slow down for me with an interval of 100ms even though there barely is any data in it.

Geometry cache - pull on attribute change.3dm (42.5 KB)
Content cache - pull on attribute change.gh (18.6 KB)

E: Adding a datadam does help a little:


E2: Though I want this to be near instant as I used to be able to use it during the beta. All I’d need is something to trigger the pull once, whenever there’s a true for the set difference. Right now, the pull creates a semi-loop, as the ‘true’ value keeps on feeding content to pull from Rhino.

I can reenable the beta behavior on ‘Model Object’ params now that we are doing a better job with the events.

A Geometry pram will expire only if the geometry changes but the Model Object will expire if any attribute changes as well.

Using a Data Dam and comparing after you should be able to compare the frozen copy after the Data Dam with the referenced one.

Could you make the user text expire on attribute change (meaning if it references Rhino geo + attributes and the latter are changed, they auto-update)? That would also get rid of the inconsistencies that User Text values change depending on when the component is placed on the canvas (before or after attribute changes).

Without that, I’d need to read, pull on change, then push so the curves are updated to update the User Text… (in theory).

@Intuos,

Are you after something like this?

1 Like

Hi @kike
any update about this?

2024-10-09 11_08_23-Window
The idea is having the user pick some curves, and those curves will have automatically added the key/value pairs nedded (with "Ensure). It works.
But then when the user manually change some values per-object, the component “User Text” never expire, never refresh.

2024-10-09 11_15_21-Window
this ^ do work. But you can’t specify the type of geometry.

2024-10-09 11_16_21-Window 2024-10-09 11_16_37-Window
those 2 ^ do not work. They won’t refresh.

“Model Object” param will refresh when an object attribute changes only if the geometry was referenced directly from the Model Object param itself.

Is this how it was meant to be?


“Query Model Objects” , similar to the old “Geometry pipeline” is not a solution because it would refresh any time ANY geometry in the document is changed… too much.

1 Like

@maje90 Could you add a sample file for me to look at?

Model Object attributes change update bug.3dm (50.6 KB)
Model Object attributes change update bug.gh (13.9 KB)

Hi @maje90,

Since there is no text on your post I will try to understand your expectations from the image. :sweat_smile:

I guess that when you say update you mean expire the solution.

  1. The Brep param only references the geometry side of the object, is currently used in many existing definition pre v8 and we can’t make it expire on any change now, that would break existing definitions and the way the users expect this to expire.
  2. The ModelObject param references the whole object, this includes the attributes and the user-text. This is why it expires when any change on the referenced object happens. Unfortunately it also expires when a change on its `Layer’ occurs (we should fix that).
  3. Brep-Guid-ModelObject, this is more convoluted. I’m aware a Guid-Geometry conversion makes the resulting Geometry being expired when its content changes, but this is assuming the Guid belongs to the active document. My intention is to avoid this kind of assumptions on how Model Content types work, in order to enable a future implementation where you can deal with multiple documents, or a Grasshopper definition can run unambiguously on a server that has no active document.

That said, we are working to make intermediate references expire when relevant changes happen without having to expire the solution from the beginning (as in case 2). This change will make expire all this three cases when you expect, if I understood you correctly.

I really do hope these kinds of ‘legacy’ decisions will be addressed in Grasshopper 2, so it will be more consistent across the board with less exceptions as to why things work differently.

1 Like