changing curve geometry from a script

   1377   4   3
User Avatar
Member
33 posts
Joined: Nov. 2008
Offline
With the old Curve node, you could change the geometry from python like so:
node.parm('coords').set(string_of_coords)

I had a working python shelf tool that would grab the point positions from some node further down the chain (for instance, an Edit SOP), then copy them back up to the original Curve SOP, allowing you to delete subsequent Edits, Transforms, etc. and bake them into the original curve. This was really useful in the case where you're drawing a bunch of control curves, then having to adjust them a bunch of times, and you don't want a pile of extra nodes cluttering up your network.

With Curve 2.0, the points seem to be generated by a zillion wrangles, operating on history entries that are stored as points in an internal Stash SOP (called parm_points). I say "history entries", because there are a lot more of them than the number of points on the curve itself, and have an "optype" attribute with values like append/delete/transform/etc.

The docs say that hou.Geometry objects are read-only except within a Python SOP, and that a Python SOP actually operates on a frozen copy of any hou.Geometry that it operates on. I assume this means that it doesn't change the contents of the original Geometry.

The Curve SOP also has a hidden parameter "parmpoints" that when you call eval() on it returns a frozen Geometry that corresponds to the "history" Geometry in the parm_points Stash. Setting the parmpoints parameter to None clears out the Stash. So there's clearly some mechanism tying the two together. But the frozen parmpoints Geometry gives read-only errors when you attempt to clear or edit it.

So I guess maybe the way to reset the Curve 2.0 node to a simple set of points with given positions would be: create a new Geometry object from scratch, populate it with the appropriate "append" and "transform" entries, then set the parmpoints parameter to the new Geometry, and hope whatever magic is in there pushes it to the Stash?

Note: While the Curve 2.0 does have better controls for editing, it's still not fully-featured: you can't select and move multiple points without it resulting in an Edit SOP being created, you can't add points to the ends of the curve (I think?) without adding them somewhere in the middle, moving the old end point, then moving the new inserted point to where the end used to be, etc. So baking subsequent changes back to the original Curve is still a useful operation.
Edited by meeotch - Dec. 4, 2022 21:57:12
User Avatar
Member
8780 posts
Joined: July 2007
Offline
geo is stashed on hidden data parameters on Curve::2.0
so you should be able to just do this
curvesop = hou.node('/obj/geo1/curve1')
editsop = hou.node('/obj/geo1/edit1')

geo = editsop.geometry()
curvesop.parm("savedstashgeo").set(geo)
# curvesop.parm("stashgeo").set(geo) # this may need to be set also, but seems to work with just savedstashgeo for me
Tomas Slancik
FX Supervisor
Method Studios, NY
User Avatar
Member
33 posts
Joined: Nov. 2008
Offline
Ha - you posted your answer while I was laboriously revising my original post to reflect the hidden parameters.

Unfortunately, I'm not seeing a hidden "savedstashgeo" parameter on Curve. Only "parmpoints" (which appears to be history), and "stashgeo". If I set "stashgeo" to editsop.geometry(), it does in fact move the output points to where they're supposed to be. But I think this is because it's loading them into a *second* Stash inside the Curve node, called "stashed_geo", and sets the "cache_switch" Switch to ignore the main processing chain.

You can then move the points around, and everything looks fine... But since the edit history is still in the parm_points Stash, but then it messes things up when the node recooks.

I thought I could set stashgeo, and then zero out parmpoints, but that just clears the entire curve.

So it feels like what's needed is some way of converting the stashgeo back into history entries in parmpoints.
User Avatar
Member
8780 posts
Joined: July 2007
Offline
meeotch
Unfortunately, I'm not seeing a hidden "savedstashgeo" parameter on Curve
it may be there only since certain version, mine is 19.5.435

curve::2.0 seems to be assuming live input and that cache is only valid for that input geo based on geo id, if there is any discrepancy with the cache it seems to try using live input and apply operations stored in "parmpoints" on it

so you can either:
- reset Curve SOP and plug stashed edited geo to its input (maybe you consider this one of the ugly workarounds, but it will make sure the further operations can again be live delta operations from the cached input)
curvesop = hou.node('/obj/geo1/curve1')
editsop = hou.node('/obj/geo1/edit1')

stash = editsop.createOutputNode("stash")
stash.parm("stashinput").pressButton()
stash.setFirstInput(None)
curvesop.setFirstInput(stash)
stash.setPosition(curvesop.position() + hou.Vector2(0, 1))

curvesop.parm("reset").pressButton()


OR

- disconnect the current input, reset the Curve SOP and set the saved stash cache, that should ignore the input branch and all the "parmpoints" operations applied to it and use the cache directly and continue applying operations just to the cache and storing a new one
Just don't ever connect the input again as it would try to prefer the live input again since it wouldnt match the cache geo id and the applied "parmpoints" will not make sense

curvesop = hou.node('/obj/geo1/curve1')
editsop = hou.node('/obj/geo1/edit1')

geo = editsop.geometry()
curvesop.setFirstInput(None)
curvesop.parm("reset").pressButton()
curvesop.parm("savedstashgeo").set(geo)
# curvesop.parm("stashgeo").set(geo) # this may need to be set also, but seems to work with just savedstashgeo for me
Edited by tamte - Dec. 5, 2022 09:48:00
Tomas Slancik
FX Supervisor
Method Studios, NY
User Avatar
Member
33 posts
Joined: Nov. 2008
Offline
Yep - I'm still in H19.0. So I guess that explains the missing savedstashgeo. No input wired to the Curve SOP in any case.

I may try it again with H19.5 - or I may try to reverse-engineer the parmpoints protocol, and build a new hou.Geometry from scratch to stuff in there. For a simple poly curve, it seems like it shouldn't be too hard: optype = appendpoints, and addpoints = a string with the point positions. Most of the other attributes seem to be zero/default values.

Out of curiosity - where in the code did you find the geo ID logic? I'm always interested to discover more gory details about houdini stuff that I haven't had to dive into before.
  • Quick Links