Loft factory question

 From:  Michael Gibson
5493.15 In reply to 5493.12 
Hi Martin,

quote:

Is the following correct?
factory.commit() calculates the result and puts it into the scene (geometryDatabase).
factory.update() just calculates the result and (with the exception of asynchronous factories like sweep or boolean) it can be assigned to a variable using factory.getCreatedObjects();
factory.calculate() also just calculates the result and it can be directly assigned to a variable.

Why can't I just write var x = factory.commit();?
Why is there an .update() and a .calculate() method when it looks like they do the same?


So it will probably make more sense if you consider that the entire factory mechanism is primarily designed to be used in an interactive command and not so much for use with custom scripting like you're doing.

The way a factory works is that you fill in the inputs, then when the inputs change you can either call .update() directly on the factory or there are also various binding mechanisms that binds a changing value to the input (like a point picker can bind its result to a factory input to push the current point the pointpicker is tracking onto the input) and those binding based methods usually automatically call factory.update() as part of its mechanisms so you don't have to call it manually in those cases.


> factory.update() just calculates the result and (with the exception of asynchronous factories like sweep or boolean)
> it can be assigned to a variable using

This part is not quite right - update calculates the result and also puts the generated output into the geometry database and deletes input objects if it's the type of command that removes inputs as well. It does all that work because it's meant to show the current result of the factory's calculation in response to a changed UI control or changed pointpicker location or things like that, and in order to display any geometry involves not just doing an isolated calculation but also putting the new objects into the geometry database. It's all the contents of the geometry database that are displayed inside of viewports, so if you want something to show up on the screen it has to not just be internally calculated but also has to go onto the geometry database.

The way regular commands are set up you can usually interactively adjust many parameters and point locations and stuff like that and see the result on the screen update, so normally there are many calls to factory.update() through this interactive part of a command.

Then usually a command can either be finished by pushing Done or it can be canceled. The way the factory mechanism works is that if you push cancel any active factory that has been created during the command will have any of its changes reverted - any generated objects will be removed from the geometry database and the original objects restored to be visible again if it was a command that removed existing objects. In order to not have that canceling mechanism be triggered you must call factory.commit() - that tells the command factory mechanism that it should consider that factory to be successfully and fully completed by the user pushing "Done" and finishing the command instead of being canceled in any way (there are various ways that things can get canceled, like with a new command being started, or the program exiting, not only just from "Cancel" being pushed).

When .commit() is called it also checks to see if there has been any previous .update() ever called and if there has not it will automatically call update() itself. It's only actually in .update() that things are actually calculated.


So anyway this whole update/cancel/commit mechanism is set up to be used in this way mostly with a command using one single factory for the command.

You're using it in a pretty different way from that, wanting to chain the results of several different factories together instead of just using one factory that was tailor-made for the command.

I've tried to add in a .calculate() method in order to help with the kind of use that you're doing - when you call .calculate() on a factory, it only creates the output objects and does not try to remove or put anything in the geometry database at all, unlike update(). So while .update() is primarily a method that gives visual results (it basically updates the screen to reflect the new factory input values), .calculate() does not do anything visual at all and only generates geometry that could then be used for other purposes in the script like intermediate calculations.

At one point I had been hoping to just have one single script mechanism for geometry creation and to be able to use the factory method for both interactive commands (with .update()/.commit()/.cancel() ) as well as using the same infrastructure for custom scripting like you're trying to do. But I think that it's not a great fit for both methods, I think that instead I'm going to implement some more direct functions in the script API to generate objects, stuff like moi.geometryDatabase.createLine( from, to ), and things like that rather than only have everything go through the factory mechanism only. But like a lot of feature areas I simply have not had enough time available yet to focus on making that new API layer. APIs are not great areas to slap together quickly because once people start using them it becomes quite difficult to make any changes in them which break existing scripts. Things that require extra care to do right tend to be time consuming and with time in short supply it can be difficult to implement time consuming areas of work...

- Michael