Grasshopper

algorithmic modeling for Rhino

I have the simplified set up as shown in the image above for my custom components.

A creates a custom object

B depends upon the object

C modifies a property of the object A creates

C is separate to A to simplify the user interface (there are a number of components that modify A, so it is better to abstract them and the user only include the ones they need).

However, I run into a problem, because if I modify C (change 1.2 to 1.3 say) then object B does not resolve itself as it gets no trigger.

I would like to hook things up so that modifying C expires the components downstream of A.

What I have in place so far is:

* When a custom object is created, add it to a dictionary that allows lookup of which component of Type A created it

* Objects passed to C

* C does it's thing

* Using the dictionary, lookup which components of Type A have passed data to component C

* Iterate over the GH_ActiveObject on the canvas, if they are of Type B check if they rely on A by doing B.DependsOn(A), if true do B.ExpireSolution(false)

* When finished checking the canvas call NewSolution(false)

However this does not seem to work. I have errors pop up saying 'an object expired during a solution'.

Is there a way of achieving what I want? My component Types are set up such that recursion is not required.

Views: 4468

Replies to This Discussion

Additionally it appears that Object B is not being recalculated. On mouse over "This object is inactive". This still happens if I use B.ExpireSolution(true).

When I force a recompute the correct data has propagated through. So it really seems to be that for some reason NewSolution is not working.

The exception you get is indeed because you're modifying the states of objects during solutions. This is not allowed.

You have to override the ExpireSolution method on component C, then iterate over all your source objects, test to see if they're of type A and then expire them as well (while taking care to not end up in an infinite expiration cycle). This will automatically expire everything dependent on A, including C.

However you also have to make sure that C executes before any components that are dependent on A execute. This will be much harder, as now all of those components have to be made aware that something like C might exist. 

I'd urge you to reconsider taking this approach, as it is counter to the way Grasshopper normally works and is thus liable to confuse people. If C modifies the data from A, why not put it in between A and B? I suspect you will keep running into problems as Grasshopper is designed on the supposition that data isn't modified in this way.

I agree that the way I have organised my components is somewhat contrary to the way Grasshopper usually works. However, the work my components are doing (some engineering computation) are not an 100% match to the flow of information that Grasshopper usually uses, hence my approach.

Forcing my users to hook up everything in series is an option, but I felt introduced a large amount of redundant work and organisation on the part of the user that reduced user friendliness, as well as introducing many ways to make mistakes.

I see the components of Type C as extensions of A, that reduce the number of inputs on A that the user is confronted with. None of the components of Type C have any outputs. As such I'd like a modification of a Type C component to trigger the same sort of recalculations as changing an input to A.

Does the fact that I only need components of Type B to be expired make things any easier? I don't actually need to expire A so can avoid some problems with infinite expiration cycles. Everything downstream of A is relatively cheap computationally so if it needs to be done a couple of times to ensure everything lines up I would be OK with that.

Is there some way of scheduling a new solution once the current solution has finished so I do not bump into the errors that are being thrown?

With the benefit of hindsight I think I would have had my calculations as a stand alone plugin that the Grasshopper components sent data to. I am a way into my project now though, and this is one of the last stumbling blocks.

I think the easiest way is to put all the logic in A. Then you can iterate over all the recipients of each output, figure out if a C object is attached to it, and modify the data before it even goes into an output parameter.

You will need additional expiration logic in C which expires A (see previous post), but that shouldn't be too difficult. I'll upload some code if I can come up with an example.

Edit: this approach actually is bad if you want to be able to use proper data matching...

It still doesn't work as it should. If more than one modifier is hooked up to components it seems to lag behind one solution. Not quite sure what's causing it...

The attached code defines two components. The 'A' component adds two numbers together. It has an output specifically meant for 'C' components, which can provide logic to modify the result. I added one 'C' type component which multiplies the result.

Attachments:

And just to go completely overboard... Here's a solution with objects that aren't components. At least it makes it obvious they are modifiers. The code has a lot of flaws, it doesn't handle all cases of addition, removal and when objects end up in different documents, but it shows the basic principle.

First, just some unconnected modifiers and a custom addition component.

Now with two modifiers hooked up. The result is (4+2)*0.1*2.0 = 1.2

And lastly with all 5 modifiers hooked up

Attachments:

Wow ....

It's going to take me a while to dig through and wrap my head around how it all works! Can see this approach working though.

mind blown.

RSS

About

Translate

Search

Photos

  • Add Photos
  • View All

Videos

  • Add Videos
  • View All

© 2024   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service