Direct manipulation flow in grashopper triggers recursive loop


Hi, I am trying to use the hand manipulations of a point in a curve to manipulate the position of all the points below it (highlighted in yellow).

For this, I planned to use the track taps to identify when a sphere is moved, its index, and the new position to alter all the neighboring spheres. However, when I try to connect the tap trigger to the function that generates the spheres, I get a “Recursive loop”, which makes sense since I am trying to modify the same object I am tracking but then, is there a way to do this?

Hi @amcard
Thanks for getting in touch. I think the simplest way to approach this would be to have a button that updates - that way it wouldn’t execute on release, but instead you could make multiple moves and then press a button in the menu to trigger the update.

Global variables have a ‘fetch’ feature that let you do this - when a component immediately downstream updates the global variable will pull the latest value. In this case inserting a stream gate acts as a simple shim.

In this sense you get recursion but it requires a step in between to trigger it.

Let me know how you go!

Cheers

Thanks Cameron!

However we are looking into a direct manipulation loop where moving one object enabled updating others in the same collection. There is not a simple way for us to specify some objects that are touchable and some that are just updating all can be touched and update others and we don’t want a button because this would interrupt the flow of the user.

Is there a way to detect the end of a drag event to trigger what the button would do otherwise?

Best

Ana

How about using the Track State component? You could connect this to a state gate to cause a component to update when the state changes.

Hi Cameron,

Thank you for the suggestion. Do you know how I could connect the Track State component to the gate to emulate the behavior or a button so it clicks every time the state is ‘Release’?

Also, I was using the track taps component because it enabled me to access the specific item that was selected and released. Is there a way to do this with the state component, or do I have to keep a local collection of the points in my script to know which one was updated?


Hi Cameron,

I created a script that checks if any of the strings in the state array is ‘Release’ and connected it to the gate. Then I used the taps component to check which element was selected. I use this to move all the objects near that object.

There are a few issues with this…The Track State component will trigger with any user interaction, so I am unsure if it’s actually dragging something. I am also getting some repeating motions that I am unsure are due to the state triggering multiple times.

You can see the update in the position that gets triggered multiple times in this video

Is there a way to better detect the click on a single object or know that an object was clicked without the recursive loop?

Blog Cameron Direct Manipulation flow v2.gh (19.0 KB)

How about this one?

When the state passes through ‘Release’ it switches the variables, which triggers the update.

drag_update.gh (12.2 KB)

A good way of doing this (where you want to update the geometry you are clicking on) is to use the Rhino document as a ‘cache’ - bake geometry (with names if references/sorting is needed) and import it in as necessary - though note you still have to be careful with recursion if you are listening to document changes!

Hi Cameron,

Thank you!. That approach to the state gate release looks cleaner than what I did.

I am not sure I understand your suggestion for baking. Forgive me, I may be too inexperienced with Grasshopper still, to bake the geometry I would have to manually right-click it and hit bake, and then import it? but what I need is to detect as soon as the State Gate is triggered which object was released (if any), is there a way to do this programmatically? For example, can I create two global variables one for the cache and one for the updated geometry?

You can see in my example I tried to use the Taps component, but I am not sure when it is triggering (with respect to the gate), and when I tried to recreate what I did in the example Grasshopper you sent, I got this error:

  1. Geometry is not synchronized. Plug in the output of a Sync Object component.
  2. Solution exception:Object reference not set to an instance of an object.

I think I have been successful in replicating the behavior of copying the position of the last clicked object using the Taps component but I still can’t detect if the object has been changed or not.

drag_update_v2.gh (25.3 KB)

You could use the centroids of the spheres and the Sets components (Set Difference?) to determine which point doesn’t exist in the previous list.

It looks like the Move2Pt doesn’t have a geometry input? Fologram doesn’t support synchronizing individual points.

Hi Cameron,

Thank you for your help before.

I have been trying to work around this issue of only triggering movement or change when the user taps and moves a sphere, not at any point that the screen is released.

I tried manually detecting the collision between the finger and the spheres but it only works when the movement is starting and I can’t preserve the variable (index) so that when the screen is released I can check if the index is a number or is null.

Could you guide me on how to do this?
drag_update_v4.gh (22.3 KB)

Hi @amcard
How about the following strategy to preserve your indices:

  • A data recorder to cache values (indices)
  • Cull the recorded list based on whether the items are null or not
  • Select the last item in the list as this was the last item touched

Hi Cameron.

Thank you, that component was just what I needed. I am trying to work on this toy example by making all the balls move in the xy pos the same amount as the ball I tap.


drag_update_v5.gh (24.9 KB)

However, the tap selection is very unstable, sometimes when I select a sphere, the tap works, but sometimes the tap selection is just null.

You can see in the video it seems to work randomly:

Do you have any recommendations on how to better do this detection of the position of the object being selected and then recovering it?