Problem scripting a 'trim' operation
 1-13  14-33  34-38

Previous
Next
 From:  Michael Gibson
3541.14 In reply to 3541.9 
Hi Dave,

> I do not believe the IDL file contains anything for
> these special methods (since they are not showing
> up in the documentation I am automatically generating).

Yeah, that's right - those are not declared in the IDL and are just implemented dynamically by some factories.

But most of the time they are things that are used by the UI, like for instance when doing a rotation the UI wants to show the current angle that the factory is rotating by if it was just given points as the inputs. So the rotate factory has a custom "angle" property that the UI can access to get put that number into the UI.

Or some things might analyze the input and tell the UI whether certain controls should be enabled or disabled.

Most of the time it's stuff more like that, Trim is kind of an exception.


> Does that mean the only way to discover them is to pore over
> the xxx.js files looking for them?

Yeah, that's the only way you would be able to find them right now.

But Trim may be the only thing that has a custom method that is needed to be triggered for the thing to actually do its work. The vast majority of those things are just for querying stuff to put in the UI for feedback while you are moving the mouse around.

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
3541.15 In reply to 3541.10 
Hi Dave, re: scripting Trim

> So which method will return me the fragment list?

So the way the command works is you put an object list for objects to trim in input 0.

Then you put in an object list for cutting objects in input 1.

Then run the generateFragments() method, this will create an internal list of fragments, and those fragments are added to the geometry database and then the next step of the regular Trim command is to pick which pieces you want to discard.

Once the selection of pieces to discard (or keep depending on the mode) is finished, then those go into a "selected fragments" list which goes into input 2. You can put in an object list there that is empty which will be the same as selecting nothing in the Trim command which splits everything up.

After that I think you should be able to call .calculate() to get the split up pieces.

So the key thing is you have to have an object list in input 2, even if it does not have any objects in it. That's just a quirk of how Trim happened to be written, it fails if it could not retrieve the object list holding the selected fragments that came from the object picker in the regular trim workflow.

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Dave Morrill (DMORRILL)
3541.16 In reply to 3541.14 
> But Trim may be the only thing that has a custom method that is needed to
> be triggered for the thing to actually do its work. The vast majority of those
> things are just for querying stuff to put in the UI for feedback while you are
> moving the mouse around.

OK, sounds like from a procedural point of view, 'trim' is the only one that might require some additional documentation.

For completeness, it might be nice to document the other stragglers as well, but since I have not got complete explanations done yet for all the methods documented in the IDL, I guess I won't worry about them until everything else has been documented.

Thanks...

- Dave Morrill
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Dave Morrill (DMORRILL)
3541.17 In reply to 3541.15 
> So the key thing is you have to have an object list in input 2, even if it does
> not have any objects in it. That's just a quirk of how Trim happened to be written,
> it fails if it could not retrieve the object list holding the selected fragments that
> came from the object picker in the regular trim workflow.

Hmm...after reading this encouraging response, I re-examined my 'trim' function and found that this was more or less what I was doing. However, it did take quite a bit more experimentation to get it to work (more or less) correctly. After much additional fiddling around and testing, I found that the following code seems to work (from a procedural perspective):

function trim ( objects, cutters, extend_lines, project_intersections ) {
var trimmer = factory( 'trim', as_list( objects ), as_list( cutters ),
object_list(), 'remove', arg( extend_lines, false ),
arg( project_intersections, true ) );
var result = trimmer.generateFragments();
var result = trimmer.calculate();
trimmer.reset();

return result;
}

The things to note about this code are:

- I bind an empty ObjectList to input 2 (fragments), but never look at it again.
- The call to 'calculate' produces the expected 'fragments' list to return.
- You MUST call 'reset' on the trim factory, otherwise the internal state of MoI gets really messed up (but doesn't crash). What I got was some fragments that could never be deleted using the UI, but moving them created new clones that could be deleted (weird). Putting the 'reset' call in fixed that behavior.

After my experience with finding that it was necessary to call 'reset' to get 'trim' to behave correctly, I began to investigate the problem I was seeing with weird 'ghost' objects when using other factories. What I found there was that the following code seems to work well for other factories (such as 'line'):

...set up factory and initialize it...
var result = f.calculate();
f.cancel();

return result;

Note that (at least in the case of 'line', which I've been doing the testing on), the call to 'cancel' seems to cure the problem with weird ghost objects showing up on the display (but a call to 'reset' did not fix the problem in this case).

In any case, this exercise seems to have made my procedural interface a little more reliable in the results it produces, so thanks again for all the explanations...

- Dave Morrill
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
3541.18 In reply to 3541.17 
Hi Dave, so what kind of ghost objects are you seeing with the line, is it an extra point object?

Are you possibly calling update() at some time before you call calculate() ?

If so then you probably should leave out the call to update() because that's meant to be used for an interactive command, so things like UI objects are created during that call, in the case of Line there is a point object created to mark the beginning point.

If you do call update(), then you could call cancel() to erase the interactive stuff like the UI geometry though.

But if you call calculate() only and avoid calling update() the UI geometry should be suppressed.


But it sounds like you may be currently getting the regular "interactive mode" stuff created by a call to update() - if you just want to generate output objects directly and have them returned to your script then call calculate() _instead_ of calling update().


- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Dave Morrill (DMORRILL)
3541.19 In reply to 3541.18 
> Hi Dave, so what kind of ghost objects are you seeing with the line, is it an extra point object?

I never use 'update' calls in my code. Previously, when I was still seeing the 'ghost' objects, the only factory call I was using was 'calculate'. Now, in addition to 'calculate', I also call 'cancel' after the call to 'calculate', which seems to eliminate the 'ghost' objects when creating things like lines.

What I mean by a 'ghost' object is a copy of a created object (like a line) that was never explicitly added to the geometry database (i.e. because only 'calculate' was used to create it), but which nevertheless shows up in the viewport.

The situation is usually as follows:

- Run a script that creates a line (using 'calculate'), but which never gets added to the geometry database.
- The viewport looks OK at this point (i.e. the created line is not visible, since it was not added to the geometry database).
- Now, using the UI (not a script), start an interactive operation, like creating another line. Click with the mouse to set the line's start point.
- At this point, the original line (created by the script in step 1), appears in all viewports.
- Complete the drawing of the interactive line by clicking to set the end point.
- At this point, the interactively created line is visible, and the 'ghost' line from step 1 disappears, never to be seen again.

Another attribute of 'ghost' geometry is that it can never be selected by clicking (no pre-selection highlight, no selection highlight), but can be selected by box dragging (normal pre-selection highlight and final selection highlight). However, once selected, the object cannot be moved, deleted, etc., although it does eventually go away, as described in the preceding series of steps. You would see this behavior immediately after running the script, when attempting to click or drag select on the empty space in the viewport where the created line should be.

So it looks like there are some circumstances where 'calculate' does put created geometry into a state where it may be displayed for a short while (usually during the extent of the next command). As I mentioned, placing a 'cancel' call after the call to 'calculate' does seem to clear up the problem (in most cases, although 'reset' seems to do a better job when using the 'trim' factory, as I mentioned before).

At this point, with the 'reset' (for 'trim') and 'cancel' (for everything else) calls in place, I have not seen any 'ghost' geometry at all. The only anomalous behavior I am seeing at this point is that when running a fairly complex script that creates lots of intermediate geometry, using a mixture of different factory operations, MoI sometimes ends up in a state that seems like it is waiting for a command to end. That is, the viewports all look fine, and may contain correctly selected objects (created by the script), but I cannot deselect existing objects or select new ones. Pressing 'enter' or 'esc' seems to exit whatever state is in in, and things are back to normal after that. I'm still investigating this, and it may be due to some other error in my script...

- Dave Morrill
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Dave Morrill (DMORRILL)
3541.20 In reply to 3541.19 
Michael,

Let me know if you want me to send you some Javascript code that can reproduce the 'ghost' object behavior. But I think you can get the behavior I described by writing a simple script that:

- Creates a 'line' factory object and sets all its inputs.
- Run the 'calculate' method on the factory object.

At that point I think you should be able to see the 'ghost' line behavior I described...

- Dave Morrill
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Dave Morrill (DMORRILL)
3541.21 In reply to 3541.20 
Just another update...

With the recent addition of the 'reset'/'cancel' calls, I'm finding my procedural scripting API is much more robust and stable now. In fact, I'm no longer seeing the last problem I mentioned, about MoI ending up in the strange 'command-like' state after running a script. As a result, I have been able to iterate really quickly now while developing my current script (since like I mentioned on another thread, I dynamically load my scripts while MoI is running).

So this is mainly a "food for thought" post for Michael...

Using my procedural API, I am finding that writing scripts many times is more like functional programming than standard procedural programming. That is, scripts tend not to have any explicit loops, but operate on lists of objects. So in many cases, ObjectList's are the "lingua franca" of the scripting world. Of course, at the lower levels of the procedural library, there are routines that must operate on the contents of the lists. In many cases, the operation that must be performed is to merge two lists into one. This can potentially create a performance bottleneck, since (as far as I know) the only way to do this is via the 'addObject' method on an ObjectList. Since Javascript (in IE) is not all that fast, I would propose adding an 'addObjects' method to ObjectList, which would add all of the objects in its ObjectList argument to the receiving ObjectList (similar to the 'addObjects' method on the GeometryDatabase object). Presumably this would be trivial to implement, but would better leverage the performance advantage of C++ over Javascript for this common scripting operation.

Again, this is just a suggestion, so feel free to take it or leave it :-)

- Dave Morrill
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
3541.22 In reply to 3541.19 
Hi Dave,

> I never use 'update' calls in my code.

Do you call .commit() though? commit() implicitly calls update() if there has not been an update done once already.

The same thing goes for commit() as update() - avoid calling that interactive mode stuff if you intend to use calculate().

The 'ghost' effect that you're describing comes from the object having the "no hit test" flag set on it - that means that it does not go into the regular hit test map so it cannot be targeted for snaps or click selections. That's to avoid things like drawing a line and having the next point you pick getting snapped on to that same line that is in the geometry database from the previous mouse move.


- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
3541.23 In reply to 3541.21 
Hi Dave, the "addObjects" method sounds like a good idea, and it should be easy to add in once I am back in development mode when v3 starts up.

It definitely helps for speed to implement as much on the C++ side as possible so that the script is more directing and gluing things together rather than doing a lot of work itself.

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Dave Morrill (DMORRILL)
3541.24 In reply to 3541.22 
Michael,

> Do you call .commit() though? commit() implicitly calls update() if there has not been an update done once already.

No, the only calls I am making on a factory object are: setInput, calculate and cancel (for most operations), and setInput, generateFragments, calculate and reset (for 'trim' operations). I verified this by grepping my procedural library for 'commit' or 'update', and did not find any matches anywhere.

BTW, I spoke too soon in my last post :-(. I am still seeing the weird post-script state where I have to hit enter or esc to get back to normal. The behavior I am seeing makes it look like it is a 'trim' operation side effect...

Upon script completion, a number of points I created are (correctly) in the selected state (i.e. highlighted). If I mouse around, I can unselect/select any of these points (which are all trim fragment endpoints), but cannot select any other geometry in the scene. Once I press enter, then everything is fine again (i.e. I can select any geometry in the scene). So it looks like 'trim' has somehow left MoI in a trim related picking state. I'll play around with 'cancel' and other operations on the factory some more to see if I can 'cure' this)...

- Dave Morrill
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Dave Morrill (DMORRILL)
3541.25 In reply to 3541.23 
> Hi Dave, the "addObjects" method sounds like a good idea, and it should be easy
> to add in once I am back in development mode when v3 starts up.

OK, great!

> It definitely helps for speed to implement as much on the C++ side as possible so
> that the script is more directing and gluing things together rather than doing a lot of work itself.

100% agreement on that. In fact, I was one of the pioneers in the use of 'glue' languages when I created the GLUE (General Language for Unifying Environments) language in 1987, back when I was with IBM Research :-)

- Dave Morrill
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
3541.26 In reply to 3541.24 
Hi Dave, so it would probably help if you could make that line script example that leaves a ghost object, so I could run it over here and check it out.

For Trim, I guess it looks like the call to generate fragments will cause UI objects to be created, for things like the endpoints of curve fragments.

The automatic setting of the disable UI geometry flag happens inside of the call to calculate(), so that's why they are not being suppressed automatically, because the fragment generation thing happens before that.

Try calling factory.disableUIGeometry(); before the generate fragments call, that should manually set the flag that disables UI geometry so I think that would then prevent those extra things from being created.

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
3541.27 In reply to 3541.25 
I never knew there was a glue language actually called GLUE ! :)

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Dave Morrill (DMORRILL)
3541.28 In reply to 3541.26 
Michael,

> Try calling factory.disableUIGeometry(); before the generate fragments call,
> that should manually set the flag that disables UI geometry so I think that
> would then prevent those extra things from being created.

I tried modifying the 'trim' function to be:
var trimmer = factory( 'trim', as_list( objects ), as_list( cutters ), 
                       object_list(), 'remove', arg( extend_lines, false ), 
                       arg( project_intersections, true ) );
trimmer.disableUIGeometry();
var result = trimmer.generateFragments();
var result = trimmer.calculate();
trimmer.reset();

but it did not have any effect on the problem. Note that the geometry I see all seems correct and expected. The problem is simply that the UI seems to be 'stuck' in some kind of picking mode at the end of the script. Pressing esc seems to end the picking mode and return everything to normal.

EDITED: 18 May 2010 by DMORRILL

  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Dave Morrill (DMORRILL)
3541.29 In reply to 3541.26 
Michael,

> Hi Dave, so it would probably help if you could make that line script example
> that leaves a ghost object, so I could run it over here and check it out.

Here's a short script that shows the problem:
var p1 = moi.vectorMath.createPoint(  0.0, 0.0, 0.0 );
var p2 = moi.vectorMath.createPoint( 10.0, 0.0, 0.0 );
var f  = moi.command.createFactory( 'line' );
f.setInput( 0, p1 );
f.setInput( 1, p2 );
var result = f.calculate();

- Run the script (the viewport should still be empty afterwards).
- Start a new line using the normal MoI UI interface. Click to set the first point somewhere.
- After the click, the line created by the script should appear in the viewport.
- Click to set the second line point.
- The script 'ghost' line should now disappear and never appear again (unless you re-run the script).

Hope that helps...

- Dave Morrill
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
3541.30 In reply to 3541.29 
Hi Dave, I see what you mean.

So there is actually an .update() being called by the system on your factory there.

Right now when a factory is created, it goes on the "active factory list", and in the pointpicker, if any binding was applied that set factory input value, update is then called on all factories in the active factory list.

That probably needs an overhaul so that it only calls update on factories that actually had an input modified. Also maybe there should be a flag that you could pass to createFactory to avoid it getting placed on the active factory list, or maybe just calling calculate() by itself should take it off the active list.

That active list is again something used for interactive commands, so that factories that are "running" are kept track of so that they can be canceled if a command is forced to exit.

The factory is removed from the active list is commit() or cancel() is called on it, so that's why calling cancel() fixes that up. You'll need to call cancel() for now to avoid unwanted updates on that factory later on.

- Michael

EDITED: 18 May 2010 by MICHAEL GIBSON

  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
3541.31 In reply to 3541.29 
And when a command ends, part of the cleanup process is that the active factory list is purged, with cancel() called on any that were still in it, that's why it stops happening after you have run some command.

That's one of the things that commit() does to make the effect of an interactive command stick around, it removes it from the active factory list so that it will not have cancel called on it when the running factories are cleared.

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Dave Morrill (DMORRILL)
3541.32 In reply to 3541.30 
Michael,

> Hi Dave, I see what you mean.

Great, at least you're aware of, and tracking, the issue now. For now, calling 'cancel' is not a problem, since it is hidden within my procedural framework. But obviously it would be good if at some future point you could fix the issue.

As I said before, there also appears to be a somewhat more annoying related issue, presumably with the trim factory, whereby the MoI UI ends up in some kind of picking mode at the end of a script.

In the script I'm working on now, I do many trim operations, all of which seem to execute correctly and produce correct results. But at the end of the script, the MoI UI is in this weird picking mode. The only geometry that can be selected or deselected are visible trim points. If I hit 'esc' then the UI resumes normal operation. No combination of adding calls to disableUpdate, disableUIGeometry, reset or cancel to the trim factory code seem to fix the problem.

I've modified (as a test) the script to not add any of the trim points it creates to the geometry database. So at the end of the script, all I see is the original geometry (since the trim points are the only things that the script is creating). I am still in the weird picking mode, but now there is nothing that can be selected or unselected, since none of the trim points I created were added to the geometry database. However, 'esc' still allows MoI to resume normal operation.

This obviously is a more serious problem, since as of now there is no work-around (other than telling the user to press 'esc' after the script finishes :-) ).

Also, I've noticed that some factories alter the selection setting of other, unrelated geometry. Can you confirm this? I noticed it when I originally wrote my script to set selection 'on' for various created objects as the script iterated its way along. At the end of the script, only the last set of selected objects were still selected; the rest had become deselected (presumably by some factories that had run after they were created and selected). When I modified the script to select all of the objects at the end, then it all worked OK. This is not necessarily a bug, but perhaps a script design consideration, so it would be good to know if that is the expected behavior...

- Dave Morrill
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
3541.33 In reply to 3541.32 
Hi Dave,

> As I said before, there also appears to be a somewhat
> more annoying related issue, presumably with the trim
> factory, whereby the MoI UI ends up in some kind of picking
> mode at the end of a script.

That's probably another side effect from the Trim factory being currently designed to work with the interactive command.

When you call generateFragments(), it sets a property called "Selection lock" on all the other objects in the geometry database. Selection lock prevents objects from having their selection changed - that helps with the Trim command because it wants you to select some of the fragments that were generated and not other objects in the model.

Selection lock is automatically cleared from everything in the cleanup step that happens when a command ends. That step is not happening with your procedural calls since you are not using them within the "command" framework.

Try something like geometryDatabase.getObjects().unlockSelection(); although that will only remove it from top-level objects, you may need to do something like put all objects and all their sub-objects also into a object list and then call .unlockSelection() on that big object list.


> Also, I've noticed that some factories alter the selection
> setting of other, unrelated geometry. Can you confirm this?

Yeah, this is what is happening in Trim. It looks like the only other one that I can find with a quick look that would also do it is Fillet when you are filleting the corners of a single curve, there is a vertex selection step there and that works similar to the fragment selection in Trim.


These various things you're running into are basically side effects from things being primarily set up and tested for use with the regular interactive commands.


- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged
 

Reply to All Reply to All

 

 
Show messages:  1-13  14-33  34-38