Kryslin's Python Questions

Another question, non-critical :

Is there a way, in the case of an error, to perform a specific task before aborting to console?

Her's why I'm asking... I was converting some of my fire and forget tools over to modeler, namely Weld Pairs and Stitch ( Weld Pairs Average). During debugging, I had a few instances of it erroring out of a mesh edit op. Should I try to run it again, It couldn't initialize another m esh edit op, and on the next try, it would crash, sometimes bringing up the crash reporter, sometimes going straight to the desk top.

Despite the PythonSDK's best efforts, I did manage to get both converted, and they both work nicely. But still, I have to ask if there is a way to close out the meshedit op before hitting the console with an error...
 
you want to wrap your task inside try/except/raise/finally. that way. if the meshop errors.. its save. and you dont have to restart.
 
Ok, the try:..except: ... finally: makes debugging thing much easier.

New question : I need to switch to point selection after I get done. I know this has to be a modeler command, called by mod_command.evaluate().

What's the character string I should be looking for? I've tried what I've used in lscript, "sel point", and variations thereof.
 
You can look at this in the file "__init__.py" of the modeler functions of the "PRIS" module.
This file is located in
"installpath_of_LW"\bin\lwsdk\pris\modeler
In this file you can search for "selpoint". What you find is how it will be handled in "PRIS". You will find many commands in this file, that you know already from LScript.

In the nuArchitect bundle I use the PRIS module which offers me most of the world of LScript.

Regards,
KANUSO
 
Last edited:
I'm aware of the PRIS module, yes. However, this isn't the selpoint/selpolygon lscript command, but switching between point mode, edge mode, and polygon mode, which was done via cmdSeq("Sel Point") / cmdSeq("Sel Polygon") in lscript.

I managed a kludge, which forced modeler into point mode; After I scan my polygons to check for curves (why doesn't lscript have fast_poly/point/edge scan?), I use mod_command.evaluate("SELPOINT CLEAR") before I iterate through the curves to get the start / end points. I uses meo.pntSelect(pID,1) to select my points while using meo.polSelect(ID,0) to deselect the polygons in that loop(meo = mesh edit operation).
 
Ok, this is more of a "Is this possible" question.

I wish to wrap the F9 /F10 rendering options; mainly I want to check to see if FiberFX is applied to the scene, and if it is disabled, ask the user if they want to enable it. When the render finishes, i'd like the script to turn FiberFX off. While I know how to toggle an applied plugin on and off, is it possible to trap the closing of the render process (either by completion, or by abort)?

The reason : Frame by frame lag after the first render with FiberFX gets intolerable - I have examples of 20-30 seconds, just scrubbing the timeline - with the more layers you add. The work around is to disable the FiberFX pixel filter, and re-enable it before rendering. I'd like to automate that process, turning it on before rendering, and turning it off after a frame or sequence is done.
 
Another question:

How does Lightwave evaluate open curves? I can properly select my span and the points needed to evaluate it, but my actual evaluation has a fair amount of error.

Keep in mind I've tried 3 different Catmull-Rom formulae - Vanilla C-R has the greatest amount of error, followed by a formula I pulled out of the include files. Closest I've gotten is centripedal C-R, but even that has a tiny bit of noticeable error. I'm probably missing something obvious, but I know other people have done it, so there must be a way to do it.

So, How?
 
Next question:

I'm currently working on converting my lscripts to python. With use of the PRIS library, things are going quite well; I prototype the scripts as one shots, then code them into a class based script.

Anyway, I've come into a problem; PRIS doesn't have something analogous to the isCurve() lScript function. I know this is a call to polyType(), and should return a True value if the polygon is of lwsdk.POLTYPE_CURB, false if otherwise.

Not all the hard to do. the PRIS library stores its mesh op session in a global variable. Can this global variable be read by a script that is using the library in which it is defined? ie:
Code:
my_mesh_op = lwsdk.pris.modeler._local_me #Assign the current pris mesh op to a local variable.

I'm not seeing much to answer the question either way between google and my Python books.

If that's the case, it'll make thing a bit easier. Otherwise, I'll have to go in and do things the harder way...

*edit* Nevermind, I ran a short test, and you can get access to the PRIS global variable for a mesh op session...
 
Last edited:
I need to get the polygon IDs associated with a point ID.

in (soon to be broken) LScript, assuming that v is a valid point ID, I would do so by using the .polygon() method.
Code:
//An Example
foreach v in points{
   assoc_polys = v.polygon();
   (...do stuff...)
}

How does one go about this in Python?

From my reading of the various SDK documents (what a disorganized mess), it appears that I have to gather a lot of data regarding selected points and the edges associated with them to get the polygon ID's associated with the point ID. Am I on the right track, or have I gone down a rabbit hole?
 
I have a question for those of you who know the python SDK...

I have discovered lwsdk.command('Generic_AddItemShape'), and have figured out all the fields to set a null's item shape parameters with it (in less than 500 lines of code!), except one:

Draw Line To.

Does anyone know it? I've tried "DrawTo=", "LineTo=", "DrawLineTo=", "Draw=","Line=" and "To=" and so far, no results. Any clues or hints?
 
Ok, I found my own answer, and I shall provide the information here...

This started out as an experiment, seeing if there was another way to add item shapes to nulls besides going through the add server/use comring path, which in LScript takes around 300 lines of code.

Turns out, there is another way, at least in Python:
Code:
lwsdk.command("Generic_AddItemShape")

This layout command has several parameters that can be added to it to fill out all the fields of the itemshape plugin. These are:
Code:
Shape= '<shape>' #Shape = Standard, Box, Ball, Pyramid, Diamond, Ring, Grid, None.  Example - Shape='Box'
Axis='<axis>' #axis = 0 for X, 1 for Y, 2 for Z
Scale='<scale>' #scale = scale of shape as a float.
Filled='<flag>' #flag = False, True
XRay='<flag>'
Opacity='<opacity>' Opacity of shape, as a float (0...1)
Label='<label>' #Label Text
Justification='<justify>' #Justify = 0 (Left),1 (Center),2(Right)
UseSelectedColor='<flag>' #flag = False, True
UseUnselectedColor='<flag>'
UseTextColor='<flag>'
SelectedColor='<r g b>' #<r g b> is three float values for the red, green, and blue colors
UnSelectedColor='<r g b>
TextColor='<r g b>'
LineTo='<Object ID>' # Object ID must be a hex value. and prefaced with 0x. <--- This is what was giving me problems.

Or, to put it into one Python Function:
Code:
import lwsdk

id2str = lambda x : lwsdk.itemid_to_str( x ) 

def addNullShape(scale=1.0, axis=0, shape=0, filled=0, sf=0, uf=0, tf=0, scol=(0,0,0), ucol=(0,0,0), tcol=(0,0,0), opacity=1.0, draw2=0, label='', justify=0, xray=0):
	s0 = ('False','True')
	lshap = ["'Standard'","'Box'", "'Ball'","'Pyramid'","'Diamond'","'Ring'","'Grid'","'None'"]
	a = "Generic_AddItemShape Replace='True'"
	a += " Shape=%s Axis='%d' Scale='%f'" % (lshap[shape],axis,scale)
	a += " Filled='%s' XRay='%s' Opacity='%f'" %(s0[filled],s0[xray],opacity)
	if label: a+= " Label='%s' Justification='%d'" % (label, justify)
	if sf: a+= " UseSelectedColor='%s' SelectedColor='%f %f %f'" % (s0[sf],scol[0],scol[1],scol[2])
	if uf: a+= " UseUnselectedColor='%s' UnselectedColor='%f %f %f'" % (s0[uf],ucol[0],ucol[1],ucol[2])
	if tf and label: a+=" UseTextColor='%s' TextColor='%f %f %f'" % (s0[tf],tcol[0],tcol[1],tcol[2])
	if draw2: a+= " LineTo='0x%s'" % id2str(draw2)
	lwsdk.command(a)

This can be optimized quite a bit, and probably made into one big formatted string command.

Code:
import lwsdk

id2str = lambda x : lwsdk.itemid_to_str( x ) 

def addNullShape(scale=1.0, axis=0, shape=0, filled=0, sf=0, uf=0, tf=0, scol=(0,0,0), ucol=(0,0,0), tcol=(0,0,0), opacity=1.0, draw2=0, label='', justify=0, xray=0):
	s0 = ('False','True')
	lshap = ["'Standard'","'Box'", "'Ball'","'Pyramid'","'Diamond'","'Ring'","'Grid'","'None'"]
	a = "Generic_AddItemShape Replace='True'"
	a += " Shape=%s Axis='%d' Scale='%f'" % (lshap[shape],axis,scale)
	a += " Filled='%s' XRay='%s' Opacity='%f'" %(s0[filled],s0[xray],opacity)
	if label: a+= " Label='%s' Justification='%d'" % (label, justify)
	if sf: a+= " UseSelectedColor='%s' SelectedColor='%f %f %f'" % (s0[sf],scol[0],scol[1],scol[2])
	if uf: a+= " UseUnselectedColor='%s' UnselectedColor='%f %f %f'" % (s0[uf],ucol[0],ucol[1],ucol[2])
	if tf and label: a+=" UseTextColor='%s' TextColor='%f %f %f'" % (s0[tf],tcol[0],tcol[1],tcol[2])
	if draw2: a+= " LineTo='0x%s'" % id2str(draw2)
	lwsdk.command(a)

lwsdk.command('AddNull A_Null')
lwsdk.command("Position 1 0 1")
sel = lwsdk.LWInterfaceInfo().selected_items()
_id = sel[len(sel)-1]
lwsdk.command("AddNull MyNull")
addNullShape (.1,1,4,0,1,1,1,(1,1,0),(0,1,0),(0,1,1),1.0,_id,'Label',2,0)
The example above adds A_Null and saves it's ID, adds MyNull and gives it an octahedron shape at .1 Scale, draws a line to A_null, and sets a text label that is right justified, and sets the colors to Yellow, Green, and Cyan.
 
Argh... I hate posting incorrect information.

This Line:
Code:
lshap = ["'Standard'","'Box'", "'Ball'","'Pyramid'","'Diamond'","'Ring'","'Grid'","'None'"]

Should read:
Code:
lshap = ["'Standard'","'Box'", "'Ball'","'Pyramid'","'Diamond'","'Tetra'","'Ring'","'Grid'","'None'"]

Apologies for any confusion.
 
I have now discovered that it is possible to write code so objectionable to the LW Python system that it refuses to even load, let alone execute.
 
A question:

I know it is possible to include multiple python scripts in one file, because OD Tools does so.

How do you accomplish this?

*edit* : I have tried making a list of serverinfo and serverrecords, having each server tag and record after each class (each class being a script), and having them all lined up at the end, in order of definition, and in the order they were C & P into the file.
 
Last edited:
Between Oliver's assistance and some boneheaded persistence on my part...

Including multiple scripts into one file is kind of a pain. Each server tag entry consists of a list containing 2 items.
Python:
ServerTagInfo = [("<plugin id", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ),
                 ("<plugin button name>", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH )]

And the server record is a dictionary...
Python:
ServerRecord = { lwsdk.CommandSequenceFactory("<plugin name>",weldpairs) : ServerTagInfo }

For multiples, you have to have a list of lists, and a dictionary that references the individual ServerTagInfo lists...
Code:
erverTagInfo = [
                (("Weld Pairs-py", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ),
                 ("Weld Pairs", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH )),
                (("Stitch-py", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ),
                 ("Stitch", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH )),
                (( "quadPoles-py", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ),
                 ( "Quadify Poles", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH )),
                (("boolcut-py", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ),
                 ("Boolean Cut", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH )),
                (("fusePolyPairs-py", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ),
                 ("Fuse Polygon Pairs", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH )),
                (( "honeycomb-py", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ),
                 ( "Honeycomb", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH )),
                (( "circPoints-py", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ),
                 ( "Circle Points", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH ))                   
                ]
ServerRecord = {
                lwsdk.CommandSequenceFactory("Weld Pairs",weldpairs) : ServerTagInfo[0],
                lwsdk.CommandSequenceFactory("Stitch", weldpairsavg) : ServerTagInfo[1],
                lwsdk.CommandSequenceFactory("Quadify Poles", quadPoles) : ServerTagInfo[2],
                lwsdk.CommandSequenceFactory("boolcut", boolcut) : ServerTagInfo[3],
                lwsdk.CommandSequenceFactory("fusePolyPairs", fusePolyPairs) : ServerTagInfo[4],
                lwsdk.CommandSequenceFactory("Honeycomb", honeycomb) : ServerTagInfo[5],
                lwsdk.CommandSequenceFactory("Circle Points", circPoints) : ServerTagInfo[6]
                }
Like so.

I wonder if I can append each entry to the list / dictionary as it's generated with a global function...
 
Back
Top